LCOV - code coverage report
Current view: top level - kern - subr_disk.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 888 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 38 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: subr_disk.c,v 1.234 2018/04/28 15:44:59 jasper Exp $  */
       2             : /*      $NetBSD: subr_disk.c,v 1.17 1996/03/16 23:17:08 christos Exp $  */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1995 Jason R. Thorpe.  All rights reserved.
       6             :  * Copyright (c) 1982, 1986, 1988, 1993
       7             :  *      The Regents of the University of California.  All rights reserved.
       8             :  * (c) UNIX System Laboratories, Inc.
       9             :  * All or some portions of this file are derived from material licensed
      10             :  * to the University of California by American Telephone and Telegraph
      11             :  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      12             :  * the permission of UNIX System Laboratories, Inc.
      13             :  *
      14             :  * Redistribution and use in source and binary forms, with or without
      15             :  * modification, are permitted provided that the following conditions
      16             :  * are met:
      17             :  * 1. Redistributions of source code must retain the above copyright
      18             :  *    notice, this list of conditions and the following disclaimer.
      19             :  * 2. Redistributions in binary form must reproduce the above copyright
      20             :  *    notice, this list of conditions and the following disclaimer in the
      21             :  *    documentation and/or other materials provided with the distribution.
      22             :  * 3. Neither the name of the University nor the names of its contributors
      23             :  *    may be used to endorse or promote products derived from this software
      24             :  *    without specific prior written permission.
      25             :  *
      26             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      27             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      28             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      29             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      30             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      31             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      32             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      33             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      34             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      35             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      36             :  * SUCH DAMAGE.
      37             :  *
      38             :  *      @(#)ufs_disksubr.c      8.5 (Berkeley) 1/21/94
      39             :  */
      40             : 
      41             : #include <sys/param.h>
      42             : #include <sys/systm.h>
      43             : #include <sys/kernel.h>
      44             : #include <sys/malloc.h>
      45             : #include <sys/fcntl.h>
      46             : #include <sys/buf.h>
      47             : #include <sys/stat.h>
      48             : #include <sys/syslog.h>
      49             : #include <sys/device.h>
      50             : #include <sys/time.h>
      51             : #include <sys/disklabel.h>
      52             : #include <sys/conf.h>
      53             : #include <sys/lock.h>
      54             : #include <sys/disk.h>
      55             : #include <sys/reboot.h>
      56             : #include <sys/dkio.h>
      57             : #include <sys/vnode.h>
      58             : #include <sys/task.h>
      59             : #include <sys/stdint.h>
      60             : 
      61             : #include <sys/socket.h>
      62             : #include <sys/socketvar.h>
      63             : 
      64             : #include <net/if.h>
      65             : 
      66             : #include <dev/rndvar.h>
      67             : #include <dev/cons.h>
      68             : 
      69             : #include <lib/libz/zlib.h>
      70             : 
      71             : #include "softraid.h"
      72             : 
      73             : #ifdef DEBUG
      74             : #define DPRINTF(x...)   printf(x)
      75             : #else
      76             : #define DPRINTF(x...)
      77             : #endif
      78             : 
      79             : /*
      80             :  * A global list of all disks attached to the system.  May grow or
      81             :  * shrink over time.
      82             :  */
      83             : struct  disklist_head disklist; /* TAILQ_HEAD */
      84             : int     disk_count;             /* number of drives in global disklist */
      85             : int     disk_change;            /* set if a disk has been attached/detached
      86             :                                  * since last we looked at this variable. This
      87             :                                  * is reset by hw_sysctl()
      88             :                                  */
      89             : 
      90             : #define DUID_SIZE 8
      91             : 
      92             : u_char  bootduid[DUID_SIZE];    /* DUID of boot disk. */
      93             : u_char  rootduid[DUID_SIZE];    /* DUID of root disk. */
      94             : 
      95             : /* softraid callback, do not use! */
      96             : void (*softraid_disk_attach)(struct disk *, int);
      97             : 
      98             : void sr_map_root(void);
      99             : 
     100             : struct disk_attach_task {
     101             :         struct task task;
     102             :         struct disk *dk;
     103             : };
     104             : 
     105             : void disk_attach_callback(void *);
     106             : 
     107             : int spoofgptlabel(struct buf *, void (*)(struct buf *), struct disklabel *);
     108             : 
     109             : int gpt_chk_mbr(struct dos_partition *, u_int64_t);
     110             : int gpt_chk_hdr(struct gpt_header *, struct disklabel *);
     111             : int gpt_chk_parts(struct gpt_header *, struct gpt_partition *);
     112             : int gpt_get_fstype(struct uuid *);
     113             : 
     114             : int duid_equal(u_char *, u_char *);
     115             : 
     116             : /*
     117             :  * Compute checksum for disk label.
     118             :  */
     119             : u_int
     120           0 : dkcksum(struct disklabel *lp)
     121             : {
     122             :         u_int16_t *start, *end;
     123             :         u_int16_t sum = 0;
     124             : 
     125           0 :         start = (u_int16_t *)lp;
     126           0 :         end = (u_int16_t *)&lp->d_partitions[lp->d_npartitions];
     127           0 :         while (start < end)
     128           0 :                 sum ^= *start++;
     129           0 :         return (sum);
     130             : }
     131             : 
     132             : int
     133           0 : initdisklabel(struct disklabel *lp)
     134             : {
     135             :         int i;
     136             : 
     137             :         /* minimal requirements for archetypal disk label */
     138           0 :         if (lp->d_secsize < DEV_BSIZE)
     139           0 :                 lp->d_secsize = DEV_BSIZE;
     140           0 :         if (DL_GETDSIZE(lp) == 0)
     141           0 :                 DL_SETDSIZE(lp, MAXDISKSIZE);
     142           0 :         if (lp->d_secpercyl == 0)
     143           0 :                 return (ERANGE);
     144           0 :         lp->d_npartitions = MAXPARTITIONS;
     145           0 :         for (i = 0; i < RAW_PART; i++) {
     146           0 :                 DL_SETPSIZE(&lp->d_partitions[i], 0);
     147           0 :                 DL_SETPOFFSET(&lp->d_partitions[i], 0);
     148             :         }
     149           0 :         if (DL_GETPSIZE(&lp->d_partitions[RAW_PART]) == 0)
     150           0 :                 DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
     151           0 :         DL_SETPOFFSET(&lp->d_partitions[RAW_PART], 0);
     152           0 :         DL_SETBSTART(lp, 0);
     153           0 :         DL_SETBEND(lp, DL_GETDSIZE(lp));
     154           0 :         lp->d_version = 1;
     155           0 :         lp->d_bbsize = 8192;
     156           0 :         lp->d_sbsize = 64*1024;                      /* XXX ? */
     157           0 :         return (0);
     158           0 : }
     159             : 
     160             : /*
     161             :  * Check an incoming block to make sure it is a disklabel, convert it to
     162             :  * a newer version if needed, etc etc.
     163             :  */
     164             : int
     165           0 : checkdisklabel(void *rlp, struct disklabel *lp, u_int64_t boundstart,
     166             :     u_int64_t boundend)
     167             : {
     168           0 :         struct disklabel *dlp = rlp;
     169             :         struct __partitionv0 *v0pp;
     170             :         struct partition *pp;
     171             :         u_int64_t disksize;
     172             :         int error = 0;
     173             :         int i;
     174             : 
     175           0 :         if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC)
     176           0 :                 error = ENOENT; /* no disk label */
     177           0 :         else if (dlp->d_npartitions > MAXPARTITIONS)
     178           0 :                 error = E2BIG;  /* too many partitions */
     179           0 :         else if (dlp->d_secpercyl == 0)
     180           0 :                 error = EINVAL; /* invalid label */
     181           0 :         else if (dlp->d_secsize == 0)
     182           0 :                 error = ENOSPC; /* disk too small */
     183           0 :         else if (dkcksum(dlp) != 0)
     184           0 :                 error = EINVAL; /* incorrect checksum */
     185             : 
     186           0 :         if (error) {
     187             :                 u_int16_t *start, *end, sum = 0;
     188             : 
     189             :                 /* If it is byte-swapped, attempt to convert it */
     190           0 :                 if (swap32(dlp->d_magic) != DISKMAGIC ||
     191           0 :                     swap32(dlp->d_magic2) != DISKMAGIC ||
     192           0 :                     swap16(dlp->d_npartitions) > MAXPARTITIONS)
     193           0 :                         return (error);
     194             : 
     195             :                 /*
     196             :                  * Need a byte-swap aware dkcksum variant
     197             :                  * inlined, because dkcksum uses a sub-field
     198             :                  */
     199           0 :                 start = (u_int16_t *)dlp;
     200           0 :                 end = (u_int16_t *)&dlp->d_partitions[
     201             :                     swap16(dlp->d_npartitions)];
     202           0 :                 while (start < end)
     203           0 :                         sum ^= *start++;
     204           0 :                 if (sum != 0)
     205           0 :                         return (error);
     206             : 
     207           0 :                 dlp->d_magic = swap32(dlp->d_magic);
     208           0 :                 dlp->d_type = swap16(dlp->d_type);
     209             : 
     210             :                 /* d_typename and d_packname are strings */
     211             : 
     212           0 :                 dlp->d_secsize = swap32(dlp->d_secsize);
     213           0 :                 dlp->d_nsectors = swap32(dlp->d_nsectors);
     214           0 :                 dlp->d_ntracks = swap32(dlp->d_ntracks);
     215           0 :                 dlp->d_ncylinders = swap32(dlp->d_ncylinders);
     216           0 :                 dlp->d_secpercyl = swap32(dlp->d_secpercyl);
     217           0 :                 dlp->d_secperunit = swap32(dlp->d_secperunit);
     218             : 
     219             :                 /* d_uid is a string */
     220             : 
     221           0 :                 dlp->d_acylinders = swap32(dlp->d_acylinders);
     222             : 
     223           0 :                 dlp->d_flags = swap32(dlp->d_flags);
     224             : 
     225           0 :                 for (i = 0; i < NDDATA; i++)
     226           0 :                         dlp->d_drivedata[i] = swap32(dlp->d_drivedata[i]);
     227             : 
     228           0 :                 dlp->d_secperunith = swap16(dlp->d_secperunith);
     229           0 :                 dlp->d_version = swap16(dlp->d_version);
     230             : 
     231           0 :                 for (i = 0; i < NSPARE; i++)
     232           0 :                         dlp->d_spare[i] = swap32(dlp->d_spare[i]);
     233             : 
     234           0 :                 dlp->d_magic2 = swap32(dlp->d_magic2);
     235             : 
     236           0 :                 dlp->d_npartitions = swap16(dlp->d_npartitions);
     237           0 :                 dlp->d_bbsize = swap32(dlp->d_bbsize);
     238           0 :                 dlp->d_sbsize = swap32(dlp->d_sbsize);
     239             : 
     240           0 :                 for (i = 0; i < MAXPARTITIONS; i++) {
     241           0 :                         pp = &dlp->d_partitions[i];
     242           0 :                         pp->p_size = swap32(pp->p_size);
     243           0 :                         pp->p_offset = swap32(pp->p_offset);
     244           0 :                         if (dlp->d_version == 0) {
     245           0 :                                 v0pp = (struct __partitionv0 *)pp;
     246           0 :                                 v0pp->p_fsize = swap32(v0pp->p_fsize);
     247           0 :                         } else {
     248           0 :                                 pp->p_offseth = swap16(pp->p_offseth);
     249           0 :                                 pp->p_sizeh = swap16(pp->p_sizeh);
     250             :                         }
     251           0 :                         pp->p_cpg = swap16(pp->p_cpg);
     252             :                 }
     253             : 
     254           0 :                 dlp->d_checksum = 0;
     255           0 :                 dlp->d_checksum = dkcksum(dlp);
     256             :                 error = 0;
     257           0 :         }
     258             : 
     259             :         /* XXX should verify lots of other fields and whine a lot */
     260             : 
     261             :         /* Initial passed in lp contains the real disk size. */
     262           0 :         disksize = DL_GETDSIZE(lp);
     263             : 
     264           0 :         if (lp != dlp)
     265           0 :                 *lp = *dlp;
     266             : 
     267           0 :         if (lp->d_version == 0) {
     268           0 :                 lp->d_version = 1;
     269           0 :                 lp->d_secperunith = 0;
     270             : 
     271           0 :                 v0pp = (struct __partitionv0 *)lp->d_partitions;
     272             :                 pp = lp->d_partitions;
     273           0 :                 for (i = 0; i < lp->d_npartitions; i++, pp++, v0pp++) {
     274           0 :                         pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(v0pp->
     275             :                             p_fsize, v0pp->p_frag);
     276           0 :                         pp->p_offseth = 0;
     277           0 :                         pp->p_sizeh = 0;
     278             :                 }
     279             :         }
     280             : 
     281             : #ifdef DEBUG
     282             :         if (DL_GETDSIZE(lp) != disksize)
     283             :                 printf("on-disk disklabel has incorrect disksize (%llu)\n",
     284             :                     DL_GETDSIZE(lp));
     285             :         if (DL_GETPSIZE(&lp->d_partitions[RAW_PART]) != disksize)
     286             :                 printf("on-disk disklabel RAW_PART has incorrect size (%llu)\n",
     287             :                     DL_GETPSIZE(&lp->d_partitions[RAW_PART]));
     288             :         if (DL_GETPOFFSET(&lp->d_partitions[RAW_PART]) != 0)
     289             :                 printf("on-disk disklabel RAW_PART offset != 0 (%llu)\n",
     290             :                     DL_GETPOFFSET(&lp->d_partitions[RAW_PART]));
     291             : #endif
     292           0 :         DL_SETDSIZE(lp, disksize);
     293           0 :         DL_SETPSIZE(&lp->d_partitions[RAW_PART], disksize);
     294           0 :         DL_SETPOFFSET(&lp->d_partitions[RAW_PART], 0);
     295           0 :         DL_SETBSTART(lp, boundstart);
     296           0 :         DL_SETBEND(lp, boundend < DL_GETDSIZE(lp) ? boundend : DL_GETDSIZE(lp));
     297             : 
     298           0 :         lp->d_checksum = 0;
     299           0 :         lp->d_checksum = dkcksum(lp);
     300           0 :         return (0);
     301           0 : }
     302             : 
     303             : /*
     304             :  * Read a disk sector.
     305             :  */
     306             : int
     307           0 : readdisksector(struct buf *bp, void (*strat)(struct buf *),
     308             :     struct disklabel *lp, u_int64_t sector)
     309             : {
     310           0 :         bp->b_blkno = DL_SECTOBLK(lp, sector);
     311           0 :         bp->b_bcount = lp->d_secsize;
     312           0 :         bp->b_error = 0;
     313           0 :         CLR(bp->b_flags, B_READ | B_WRITE | B_DONE | B_ERROR);
     314           0 :         SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
     315             : 
     316           0 :         (*strat)(bp);
     317             : 
     318           0 :         return (biowait(bp));
     319             : }
     320             : 
     321             : /*
     322             :  * If dos partition table requested, attempt to load it and
     323             :  * find disklabel inside a DOS partition. Return buffer
     324             :  * for use in signalling errors if requested.
     325             :  *
     326             :  * We would like to check if each MBR has a valid BOOT_MAGIC, but
     327             :  * we cannot because it doesn't always exist. So.. we assume the
     328             :  * MBR is valid.
     329             :  */
     330             : int
     331           0 : readdoslabel(struct buf *bp, void (*strat)(struct buf *),
     332             :     struct disklabel *lp, daddr_t *partoffp, int spoofonly)
     333             : {
     334             :         struct disklabel *gptlp;
     335           0 :         u_int64_t dospartoff = 0, dospartend = DL_GETBEND(lp);
     336             :         int i, ourpart = -1, wander = 1, n = 0, loop = 0, offset;
     337           0 :         struct dos_partition dp[NDOSPART], *dp2;
     338             :         u_int64_t sector = DOSBBSECTOR;
     339             :         u_int32_t extoff = 0;
     340             :         int error;
     341             : 
     342           0 :         if (lp->d_secpercyl == 0)
     343           0 :                 return (EINVAL);        /* invalid label */
     344           0 :         if (lp->d_secsize == 0)
     345           0 :                 return (ENOSPC);        /* disk too small */
     346             : 
     347             :         /* do DOS partitions in the process of getting disklabel? */
     348             : 
     349             :         /*
     350             :          * Read dos partition table, follow extended partitions.
     351             :          * Map the partitions to disklabel entries i-p
     352             :          */
     353           0 :         while (wander && loop < DOS_MAXEBR) {
     354           0 :                 loop++;
     355             :                 wander = 0;
     356           0 :                 if (sector < extoff)
     357           0 :                         sector = extoff;
     358             : 
     359             :                 /* read MBR/EBR */
     360           0 :                 error = readdisksector(bp, strat, lp, sector);
     361           0 :                 if (error) {
     362           0 : /*wrong*/               if (partoffp)
     363           0 : /*wrong*/                       *partoffp = -1;
     364           0 :                         return (error);
     365             :                 }
     366             : 
     367           0 :                 bcopy(bp->b_data + DOSPARTOFF, dp, sizeof(dp));
     368             : 
     369           0 :                 if (n == 0 && sector == DOSBBSECTOR) {
     370             :                         u_int16_t mbrtest;
     371             : 
     372             :                         /* Check the end of sector marker. */
     373           0 :                         mbrtest = ((bp->b_data[510] << 8) & 0xff00) |
     374           0 :                             (bp->b_data[511] & 0xff);
     375           0 :                         if (mbrtest != 0x55aa)
     376           0 :                                 goto notmbr;
     377             : 
     378           0 :                         if (gpt_chk_mbr(dp, DL_GETDSIZE(lp)) != 0)
     379           0 :                                 goto notgpt;
     380             : 
     381           0 :                         gptlp = malloc(sizeof(struct disklabel), M_DEVBUF,
     382             :                             M_NOWAIT);
     383           0 :                         if (gptlp == NULL)
     384           0 :                                 return (ENOMEM);
     385           0 :                         *gptlp = *lp;
     386           0 :                         error = spoofgptlabel(bp, strat, gptlp);
     387           0 :                         if (error == 0) {
     388           0 :                                 dospartoff = DL_GETBSTART(gptlp);
     389           0 :                                 dospartend = DL_GETBEND(gptlp);
     390           0 :                                 if (partoffp == 0)
     391           0 :                                         *lp = *gptlp;
     392           0 :                                 free(gptlp, M_DEVBUF,
     393             :                                     sizeof(struct disklabel));
     394           0 :                                 if (partoffp && dospartoff == 0)
     395           0 :                                         return (ENXIO);
     396           0 :                                 goto notfat;
     397             :                         } else {
     398           0 :                                 free(gptlp, M_DEVBUF,
     399             :                                     sizeof(struct disklabel));
     400           0 :                                 goto notmbr;
     401             :                         }
     402             :                 }
     403             : 
     404             : notgpt:
     405           0 :                 if (ourpart == -1) {
     406             :                         /* Search for our MBR partition */
     407           0 :                         for (dp2=dp, i=0; i < NDOSPART && ourpart == -1;
     408           0 :                             i++, dp2++)
     409           0 :                                 if (letoh32(dp2->dp_size) &&
     410           0 :                                     dp2->dp_typ == DOSPTYP_OPENBSD)
     411           0 :                                         ourpart = i;
     412           0 :                         if (ourpart == -1)
     413             :                                 goto donot;
     414             :                         /*
     415             :                          * This is our MBR partition. need sector
     416             :                          * address for SCSI/IDE, cylinder for
     417             :                          * ESDI/ST506/RLL
     418             :                          */
     419           0 :                         dp2 = &dp[ourpart];
     420           0 :                         dospartoff = letoh32(dp2->dp_start) + sector;
     421           0 :                         dospartend = dospartoff + letoh32(dp2->dp_size);
     422             : 
     423             :                         /*
     424             :                          * Record the OpenBSD partition's placement (in
     425             :                          * 512-byte blocks!) for the caller. No need to
     426             :                          * finish spoofing.
     427             :                          */
     428           0 :                         if (partoffp) {
     429           0 :                                 *partoffp = DL_SECTOBLK(lp, dospartoff);
     430           0 :                                 return (0);
     431             :                         }
     432             : 
     433           0 :                         if (lp->d_ntracks == 0)
     434           0 :                                 lp->d_ntracks = dp2->dp_ehd + 1;
     435           0 :                         if (lp->d_nsectors == 0)
     436           0 :                                 lp->d_nsectors = DPSECT(dp2->dp_esect);
     437           0 :                         if (lp->d_secpercyl == 0)
     438           0 :                                 lp->d_secpercyl = lp->d_ntracks *
     439           0 :                                     lp->d_nsectors;
     440             :                 }
     441             : donot:
     442             :                 /*
     443             :                  * In case the disklabel read below fails, we want to
     444             :                  * provide a fake label in i-p.
     445             :                  */
     446           0 :                 for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
     447             :                         struct partition *pp;
     448             :                         u_int8_t fstype;
     449             : 
     450           0 :                         if (dp2->dp_typ == DOSPTYP_OPENBSD ||
     451           0 :                             dp2->dp_typ == DOSPTYP_EFI)
     452           0 :                                 continue;
     453           0 :                         if (letoh32(dp2->dp_size) > DL_GETDSIZE(lp))
     454           0 :                                 continue;
     455           0 :                         if (letoh32(dp2->dp_start) > DL_GETDSIZE(lp))
     456           0 :                                 continue;
     457           0 :                         if (letoh32(dp2->dp_size) == 0)
     458           0 :                                 continue;
     459             : 
     460           0 :                         switch (dp2->dp_typ) {
     461             :                         case DOSPTYP_UNUSED:
     462             :                                 fstype = FS_UNUSED;
     463           0 :                                 break;
     464             : 
     465             :                         case DOSPTYP_LINUX:
     466             :                                 fstype = FS_EXT2FS;
     467           0 :                                 break;
     468             : 
     469             :                         case DOSPTYP_NTFS:
     470             :                                 fstype = FS_NTFS;
     471           0 :                                 break;
     472             : 
     473             :                         case DOSPTYP_EFISYS:
     474             :                         case DOSPTYP_FAT12:
     475             :                         case DOSPTYP_FAT16S:
     476             :                         case DOSPTYP_FAT16B:
     477             :                         case DOSPTYP_FAT16L:
     478             :                         case DOSPTYP_FAT32:
     479             :                         case DOSPTYP_FAT32L:
     480             :                                 fstype = FS_MSDOS;
     481           0 :                                 break;
     482             :                         case DOSPTYP_EXTEND:
     483             :                         case DOSPTYP_EXTENDL:
     484           0 :                                 sector = letoh32(dp2->dp_start) + extoff;
     485           0 :                                 if (!extoff) {
     486             :                                         extoff = letoh32(dp2->dp_start);
     487             :                                         sector = 0;
     488           0 :                                 }
     489             :                                 wander = 1;
     490           0 :                                 continue;
     491             :                                 break;
     492             :                         default:
     493             :                                 fstype = FS_OTHER;
     494           0 :                                 break;
     495             :                         }
     496             : 
     497             :                         /*
     498             :                          * Don't set fstype/offset/size when just looking for
     499             :                          * the offset of the OpenBSD partition. It would
     500             :                          * invalidate the disklabel checksum!
     501             :                          *
     502             :                          * Don't try to spoof more than 8 partitions, i.e.
     503             :                          * 'i' -'p'.
     504             :                          */
     505           0 :                         if (partoffp || n >= 8)
     506           0 :                                 continue;
     507             : 
     508           0 :                         pp = &lp->d_partitions[8+n];
     509           0 :                         n++;
     510           0 :                         pp->p_fstype = fstype;
     511           0 :                         if (letoh32(dp2->dp_start))
     512           0 :                                 DL_SETPOFFSET(pp,
     513             :                                     letoh32(dp2->dp_start) + sector);
     514           0 :                         DL_SETPSIZE(pp, letoh32(dp2->dp_size));
     515           0 :                 }
     516             :         }
     517             : 
     518             : notmbr:
     519           0 :         if (n == 0 && sector == DOSBBSECTOR && ourpart == -1) {
     520             :                 u_int16_t fattest;
     521             : 
     522             :                 /* Check for a valid initial jmp instruction. */
     523           0 :                 switch ((u_int8_t)bp->b_data[0]) {
     524             :                 case 0xeb:
     525             :                         /*
     526             :                          * Two-byte jmp instruction. The 2nd byte is the number
     527             :                          * of bytes to jmp and the 3rd byte must be a NOP.
     528             :                          */
     529           0 :                         if ((u_int8_t)bp->b_data[2] != 0x90)
     530           0 :                                 goto notfat;
     531             :                         break;
     532             :                 case 0xe9:
     533             :                         /*
     534             :                          * Three-byte jmp instruction. The next two bytes are a
     535             :                          * little-endian 16 bit value.
     536             :                          */
     537             :                         break;
     538             :                 default:
     539           0 :                         goto notfat;
     540             :                         break;
     541             :                 }
     542             : 
     543             :                 /* Check for a valid bytes per sector value. */
     544           0 :                 fattest = ((bp->b_data[12] << 8) & 0xff00) |
     545           0 :                     (bp->b_data[11] & 0xff);
     546           0 :                 if (fattest < 512 || fattest > 4096 || (fattest % 512 != 0))
     547           0 :                         goto notfat;
     548             : 
     549           0 :                 if (partoffp)
     550           0 :                         return (ENXIO); /* No place for disklabel on FAT! */
     551             : 
     552           0 :                 DL_SETPSIZE(&lp->d_partitions['i' - 'a'],
     553             :                     DL_GETPSIZE(&lp->d_partitions[RAW_PART]));
     554           0 :                 DL_SETPOFFSET(&lp->d_partitions['i' - 'a'], 0);
     555           0 :                 lp->d_partitions['i' - 'a'].p_fstype = FS_MSDOS;
     556             : 
     557             :                 spoofonly = 1;  /* No disklabel to read from disk. */
     558           0 :         }
     559             : 
     560             : notfat:
     561             :         /* record the OpenBSD partition's placement for the caller */
     562           0 :         if (partoffp)
     563           0 :                 *partoffp = DL_SECTOBLK(lp, dospartoff);
     564             :         else {
     565           0 :                 DL_SETBSTART(lp, dospartoff);
     566           0 :                 DL_SETBEND(lp, (dospartend < DL_GETDSIZE(lp)) ? dospartend :
     567             :                     DL_GETDSIZE(lp));
     568             :         }
     569             : 
     570             :         /* don't read the on-disk label if we are in spoofed-only mode */
     571           0 :         if (spoofonly)
     572           0 :                 return (0);
     573             : 
     574           0 :         error = readdisksector(bp, strat, lp, dospartoff +
     575           0 :             DL_BLKTOSEC(lp, DOS_LABELSECTOR));
     576           0 :         if (error)
     577           0 :                 return (bp->b_error);
     578             : 
     579           0 :         offset = DL_BLKOFFSET(lp, DOS_LABELSECTOR);
     580           0 :         error = checkdisklabel(bp->b_data + offset, lp,
     581           0 :             DL_GETBSTART((struct disklabel*)(bp->b_data+offset)),
     582           0 :             DL_GETBEND((struct disklabel *)(bp->b_data+offset)));
     583             : 
     584           0 :         return (error);
     585           0 : }
     586             : 
     587             : /*
     588             :  * Returns 0 if the MBR with the provided partition array is a GPT protective
     589             :  * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
     590             :  * one MBR partition, an EFI partition that either covers the whole disk or as
     591             :  * much of it as is possible with a 32bit size field.
     592             :  *
     593             :  * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
     594             :  */
     595             : int
     596           0 : gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize)
     597             : {
     598             :         struct dos_partition *dp2;
     599             :         int efi, found, i;
     600             :         u_int32_t psize;
     601             : 
     602             :         found = efi = 0;
     603           0 :         for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
     604           0 :                 if (dp2->dp_typ == DOSPTYP_UNUSED)
     605             :                         continue;
     606           0 :                 found++;
     607           0 :                 if (dp2->dp_typ != DOSPTYP_EFI)
     608             :                         continue;
     609           0 :                 psize = letoh32(dp2->dp_size);
     610           0 :                 if (psize == (dsize - 1) ||
     611           0 :                     psize == UINT32_MAX) {
     612           0 :                         if (letoh32(dp2->dp_start) == 1)
     613           0 :                                 efi++;
     614             :                 }
     615             :         }
     616           0 :         if (found == 1 && efi == 1)
     617           0 :                 return (0);
     618             : 
     619           0 :         return (1);
     620           0 : }
     621             : 
     622             : int
     623           0 : gpt_chk_hdr(struct gpt_header *gh, struct disklabel *lp)
     624             : {
     625             :         uint64_t ghpartlba;
     626             :         uint64_t ghlbaend, ghlbastart;
     627             :         uint32_t orig_gh_csum;
     628             :         uint32_t ghsize, ghpartsize, ghpartspersec;
     629             : 
     630           0 :         if (letoh64(gh->gh_sig) != GPTSIGNATURE)
     631           0 :                 return (EINVAL);
     632             : 
     633           0 :         if (letoh32(gh->gh_rev) != GPTREVISION)
     634           0 :                 return (EINVAL);
     635             : 
     636           0 :         ghsize = letoh32(gh->gh_size);
     637           0 :         ghpartsize = letoh32(gh->gh_part_size);
     638           0 :         ghpartspersec = lp->d_secsize / ghpartsize;
     639           0 :         ghpartlba = letoh64(gh->gh_part_lba);
     640           0 :         ghlbaend = letoh64(gh->gh_lba_end);
     641           0 :         ghlbastart = letoh64(gh->gh_lba_start);
     642             : 
     643           0 :         if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header))
     644           0 :                 return (EINVAL);
     645             : 
     646           0 :         orig_gh_csum = gh->gh_csum;
     647           0 :         gh->gh_csum = 0;
     648           0 :         gh->gh_csum = crc32(0, (unsigned char *)gh, ghsize);
     649             : 
     650           0 :         if (orig_gh_csum != gh->gh_csum)
     651           0 :                 return (EINVAL);
     652             : 
     653           0 :         if (ghlbastart >= DL_GETDSIZE(lp) ||
     654           0 :             ghlbaend >= DL_GETDSIZE(lp) ||
     655           0 :             ghpartlba >= DL_GETDSIZE(lp))
     656           0 :                 return (EINVAL);
     657             : 
     658             :         /*
     659             :         * Size per partition entry shall be 128*(2**n) with n >= 0.
     660             :         * We don't support partition entries larger than block size.
     661             :         */
     662           0 :         if (ghpartsize % GPTMINPARTSIZE || ghpartsize > lp->d_secsize
     663           0 :             || ghpartspersec == 0) {
     664             :                 DPRINTF("invalid partition size\n");
     665           0 :                 return (EINVAL);
     666             :         }
     667             : 
     668             :         /* XXX: we don't support multiples of GPTMINPARTSIZE yet */
     669           0 :         if (ghpartsize != GPTMINPARTSIZE) {
     670             :                 DPRINTF("partition sizes larger than %d bytes are not "
     671             :                     "supported", GPTMINPARTSIZE);
     672           0 :                 return (EINVAL);
     673             :         }
     674             : 
     675           0 :         if (letoh64(gh->gh_lba_alt) >= DL_GETDSIZE(lp)) {
     676             :                 DPRINTF("alternate header's position is bogus\n");
     677           0 :                 return (EINVAL);
     678             :         }
     679             : 
     680           0 :         return 0;
     681           0 : }
     682             : 
     683             : int
     684           0 : gpt_chk_parts(struct gpt_header *gh, struct gpt_partition *gp)
     685             : {
     686             :         u_int32_t checksum;
     687           0 :         checksum = crc32(0, (unsigned char *)gp,
     688           0 :             letoh32(gh->gh_part_num) * letoh32(gh->gh_part_size));
     689             : 
     690           0 :         if (checksum != gh->gh_part_csum)
     691           0 :                 return (EINVAL);
     692             : 
     693           0 :         return 0;
     694           0 : }
     695             : 
     696             : int
     697           0 : gpt_get_fstype(struct uuid *uuid_part)
     698             : {
     699             :         static int init = 0;
     700             :         static struct uuid uuid_openbsd, uuid_msdos, uuid_chromefs,
     701             :             uuid_linux, uuid_hfs, uuid_unused, uuid_efi_system;
     702             :         static const uint8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD;
     703             :         static const uint8_t gpt_uuid_msdos[] = GPT_UUID_MSDOS;
     704             :         static const uint8_t gpt_uuid_chromerootfs[] = GPT_UUID_CHROMEROOTFS;
     705             :         static const uint8_t gpt_uuid_linux[] = GPT_UUID_LINUX;
     706             :         static const uint8_t gpt_uuid_hfs[] = GPT_UUID_APPLE_HFS;
     707             :         static const uint8_t gpt_uuid_unused[] = GPT_UUID_UNUSED;
     708             :         static const uint8_t gpt_uuid_efi_system[] = GPT_UUID_EFI_SYSTEM;
     709             : 
     710           0 :         if (init == 0) {
     711           0 :                 uuid_dec_be(gpt_uuid_openbsd, &uuid_openbsd);
     712           0 :                 uuid_dec_be(gpt_uuid_msdos, &uuid_msdos);
     713           0 :                 uuid_dec_be(gpt_uuid_chromerootfs, &uuid_chromefs);
     714           0 :                 uuid_dec_be(gpt_uuid_linux, &uuid_linux);
     715           0 :                 uuid_dec_be(gpt_uuid_hfs, &uuid_hfs);
     716           0 :                 uuid_dec_be(gpt_uuid_unused, &uuid_unused);
     717           0 :                 uuid_dec_be(gpt_uuid_efi_system, &uuid_efi_system);
     718           0 :                 init = 1;
     719           0 :         }
     720             : 
     721           0 :         if (!memcmp(uuid_part, &uuid_unused, sizeof(struct uuid)))
     722           0 :                 return FS_UNUSED;
     723           0 :         else if (!memcmp(uuid_part, &uuid_openbsd, sizeof(struct uuid)))
     724           0 :                 return FS_BSDFFS;
     725           0 :         else if (!memcmp(uuid_part, &uuid_msdos, sizeof(struct uuid)))
     726           0 :                 return FS_MSDOS;
     727           0 :         else if (!memcmp(uuid_part, &uuid_chromefs, sizeof(struct uuid)))
     728           0 :                 return FS_EXT2FS;
     729           0 :         else if (!memcmp(uuid_part, &uuid_linux, sizeof(struct uuid)))
     730           0 :                 return FS_EXT2FS;
     731           0 :         else if (!memcmp(uuid_part, &uuid_hfs, sizeof(struct uuid)))
     732           0 :                 return FS_HFS;
     733           0 :         else if (!memcmp(uuid_part, &uuid_efi_system, sizeof(struct uuid)))
     734           0 :                 return FS_MSDOS;
     735             :         else
     736           0 :                 return FS_OTHER;
     737           0 : }
     738             : 
     739             : /*
     740             :  * Spoof a disklabel based on the GPT information on the disk.
     741             :  */
     742             : int
     743           0 : spoofgptlabel(struct buf *bp, void (*strat)(struct buf *),
     744             :     struct disklabel *lp)
     745             : {
     746             :         static const u_int8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD;
     747           0 :         struct gpt_header gh;
     748           0 :         struct uuid uuid_part, uuid_openbsd;
     749             :         struct gpt_partition *gp, *gp_tmp;
     750             :         struct partition *pp;
     751             :         size_t gpsz;
     752             :         u_int64_t ghlbaend, ghlbastart, gptpartoff, gptpartend, sector;
     753             :         u_int64_t start, end;
     754             :         int i, altheader = 0, error, n;
     755             :         uint32_t ghpartnum;
     756             : 
     757           0 :         uuid_dec_be(gpt_uuid_openbsd, &uuid_openbsd);
     758             : 
     759           0 :         for (sector = GPTSECTOR; ; sector = DL_GETDSIZE(lp)-1, altheader = 1) {
     760             :                 uint64_t ghpartlba;
     761             :                 uint32_t ghpartsize;
     762             :                 uint32_t ghpartspersec;
     763             : 
     764           0 :                 error = readdisksector(bp, strat, lp, sector);
     765           0 :                 if (error) {
     766             :                         DPRINTF("error reading from disk\n");
     767           0 :                         return (error);
     768             :                 }
     769             : 
     770           0 :                 bcopy(bp->b_data, &gh, sizeof(gh));
     771             : 
     772           0 :                 if (gpt_chk_hdr(&gh, lp)) {
     773           0 :                         if (altheader) {
     774             :                                 DPRINTF("alternate header also broken\n");
     775           0 :                                 return (EINVAL);
     776             :                         }
     777           0 :                         continue;
     778             :                 }
     779             : 
     780           0 :                 ghpartsize = letoh32(gh.gh_part_size);
     781           0 :                 ghpartspersec = lp->d_secsize / ghpartsize;
     782           0 :                 ghpartnum = letoh32(gh.gh_part_num);
     783           0 :                 ghpartlba = letoh64(gh.gh_part_lba);
     784           0 :                 ghlbaend = letoh64(gh.gh_lba_end);
     785           0 :                 ghlbastart = letoh64(gh.gh_lba_start);
     786             : 
     787             :                 /* read GPT partition entry array */
     788           0 :                 gp = mallocarray(ghpartnum, sizeof(struct gpt_partition),
     789             :                     M_DEVBUF, M_NOWAIT|M_ZERO);
     790           0 :                 if (gp == NULL)
     791           0 :                         return (ENOMEM);
     792           0 :                 gpsz = ghpartnum * sizeof(struct gpt_partition);
     793             : 
     794             :                 /*
     795             :                 * XXX:  Fails if # of partition entries is not a multiple of
     796             :                 *       ghpartspersec.
     797             :                 */
     798             :                 sector = ghpartlba;
     799           0 :                 for (i = 0; i < ghpartnum / ghpartspersec; i++, sector++) {
     800           0 :                         error = readdisksector(bp, strat, lp, sector);
     801           0 :                         if (error) {
     802           0 :                                 free(gp, M_DEVBUF, gpsz);
     803           0 :                                 return (error);
     804             :                         }
     805             : 
     806           0 :                         bcopy(bp->b_data, gp + i * ghpartspersec,
     807           0 :                             ghpartspersec * sizeof(struct gpt_partition));
     808             :                 }
     809             : 
     810           0 :                 if (gpt_chk_parts(&gh, gp)) {
     811           0 :                         free(gp, M_DEVBUF, gpsz);
     812           0 :                         if (altheader) {
     813             :                                 DPRINTF("alternate partition entries are also "
     814             :                                     "broken\n");
     815           0 :                                 return (EINVAL);
     816             :                         }
     817           0 :                         continue;
     818             :                 }
     819           0 :                 break;
     820             :         }
     821             : 
     822             :         /* Find OpenBSD partition and spoof others along the way. */
     823             :         n = 0;
     824             :         gptpartoff = 0;
     825           0 :         gptpartend = DL_GETBEND(lp);
     826           0 :         for (gp_tmp = gp, i = 0; i < ghpartnum; gp_tmp++, i++) {
     827           0 :                 start = letoh64(gp_tmp->gp_lba_start);
     828           0 :                 end = letoh64(gp_tmp->gp_lba_end);
     829           0 :                 if (start > end || start < ghlbastart || end > ghlbaend)
     830             :                         continue; /* entry invalid */
     831             : 
     832           0 :                 uuid_dec_le(&gp_tmp->gp_type, &uuid_part);
     833           0 :                 if (!memcmp(&uuid_part, &uuid_openbsd, sizeof(struct uuid))) {
     834           0 :                         if (gptpartoff == 0) {
     835             :                                 gptpartoff = start;
     836           0 :                                 gptpartend = end + 1;
     837           0 :                         }
     838             :                         continue; /* Do *NOT* spoof OpenBSD partitions! */
     839             :                 }
     840             : 
     841             :                  /*
     842             :                  * Don't try to spoof more than 8 partitions, i.e.
     843             :                  * 'i' -'p'.
     844             :                  */
     845           0 :                 if (n >= 8)
     846             :                         continue;
     847             : 
     848           0 :                 pp = &lp->d_partitions[8+n];
     849           0 :                 n++;
     850           0 :                 pp->p_fstype = gpt_get_fstype(&uuid_part);
     851           0 :                 DL_SETPOFFSET(pp, start);
     852           0 :                 DL_SETPSIZE(pp, end - start + 1);
     853           0 :         }
     854             : 
     855           0 :         free(gp, M_DEVBUF, gpsz);
     856             : 
     857           0 :         DL_SETBSTART(lp, gptpartoff);
     858           0 :         DL_SETBEND(lp, (gptpartend < DL_GETDSIZE(lp)) ? gptpartend :
     859             :             DL_GETDSIZE(lp));
     860             : 
     861           0 :         return (0);
     862           0 : }
     863             : 
     864             : /*
     865             :  * Check new disk label for sensibility before setting it.
     866             :  */
     867             : int
     868           0 : setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_int openmask)
     869             : {
     870             :         struct partition *opp, *npp;
     871             :         struct disk *dk;
     872             :         int i;
     873             : 
     874             :         /* sanity clause */
     875           0 :         if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 ||
     876           0 :             (nlp->d_secsize % DEV_BSIZE) != 0)
     877           0 :                 return (EINVAL);
     878             : 
     879             :         /* special case to allow disklabel to be invalidated */
     880           0 :         if (nlp->d_magic == 0xffffffff) {
     881           0 :                 *olp = *nlp;
     882           0 :                 return (0);
     883             :         }
     884             : 
     885           0 :         if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
     886           0 :             dkcksum(nlp) != 0)
     887           0 :                 return (EINVAL);
     888             : 
     889             :         /* XXX missing check if other dos partitions will be overwritten */
     890             : 
     891           0 :         for (i = 0; i < MAXPARTITIONS; i++) {
     892           0 :                 opp = &olp->d_partitions[i];
     893           0 :                 npp = &nlp->d_partitions[i];
     894           0 :                 if ((openmask & (1 << i)) &&
     895           0 :                     (DL_GETPOFFSET(npp) != DL_GETPOFFSET(opp) ||
     896           0 :                     DL_GETPSIZE(npp) < DL_GETPSIZE(opp)))
     897           0 :                         return (EBUSY);
     898             :                 /*
     899             :                  * Copy internally-set partition information
     900             :                  * if new label doesn't include it.             XXX
     901             :                  */
     902           0 :                 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
     903           0 :                         npp->p_fragblock = opp->p_fragblock;
     904           0 :                         npp->p_cpg = opp->p_cpg;
     905           0 :                 }
     906             :         }
     907             : 
     908             :         /* Generate a UID if the disklabel does not already have one. */
     909           0 :         if (duid_iszero(nlp->d_uid)) {
     910           0 :                 do {
     911           0 :                         arc4random_buf(nlp->d_uid, sizeof(nlp->d_uid));
     912           0 :                         TAILQ_FOREACH(dk, &disklist, dk_link)
     913           0 :                                 if (dk->dk_label &&
     914           0 :                                     duid_equal(dk->dk_label->d_uid, nlp->d_uid))
     915             :                                         break;
     916           0 :                 } while (dk != NULL || duid_iszero(nlp->d_uid));
     917             :         }
     918             : 
     919             :         /* Preserve the disk size and RAW_PART values. */
     920           0 :         DL_SETDSIZE(nlp, DL_GETDSIZE(olp));
     921           0 :         npp = &nlp->d_partitions[RAW_PART];
     922           0 :         DL_SETPOFFSET(npp, 0);
     923           0 :         DL_SETPSIZE(npp, DL_GETDSIZE(nlp));
     924             : 
     925           0 :         nlp->d_checksum = 0;
     926           0 :         nlp->d_checksum = dkcksum(nlp);
     927           0 :         *olp = *nlp;
     928             : 
     929           0 :         disk_change = 1;
     930             : 
     931           0 :         return (0);
     932           0 : }
     933             : 
     934             : /*
     935             :  * Determine the size of the transfer, and make sure it is within the
     936             :  * boundaries of the partition. Adjust transfer if needed, and signal errors or
     937             :  * early completion.
     938             :  */
     939             : int
     940           0 : bounds_check_with_label(struct buf *bp, struct disklabel *lp)
     941             : {
     942           0 :         struct partition *p = &lp->d_partitions[DISKPART(bp->b_dev)];
     943             :         daddr_t partblocks, sz;
     944             : 
     945             :         /* Avoid division by zero, negative offsets, and negative sizes. */
     946           0 :         if (lp->d_secpercyl == 0 || bp->b_blkno < 0 || bp->b_bcount < 0)
     947             :                 goto bad;
     948             : 
     949             :         /* Ensure transfer is a whole number of aligned sectors. */
     950           0 :         if ((bp->b_blkno % DL_BLKSPERSEC(lp)) != 0 ||
     951           0 :             (bp->b_bcount % lp->d_secsize) != 0)
     952             :                 goto bad;
     953             : 
     954             :         /* Ensure transfer starts within partition boundary. */
     955           0 :         partblocks = DL_SECTOBLK(lp, DL_GETPSIZE(p));
     956           0 :         if (bp->b_blkno > partblocks)
     957             :                 goto bad;
     958             : 
     959             :         /* If exactly at end of partition or null transfer, return EOF. */
     960           0 :         if (bp->b_blkno == partblocks || bp->b_bcount == 0)
     961             :                 goto done;
     962             : 
     963             :         /* Truncate request if it extends past the end of the partition. */
     964           0 :         sz = bp->b_bcount >> DEV_BSHIFT;
     965           0 :         if (sz > partblocks - bp->b_blkno) {
     966             :                 sz = partblocks - bp->b_blkno;
     967           0 :                 bp->b_bcount = sz << DEV_BSHIFT;
     968           0 :         }
     969             : 
     970           0 :         return (0);
     971             : 
     972             :  bad:
     973           0 :         bp->b_error = EINVAL;
     974           0 :         bp->b_flags |= B_ERROR;
     975             :  done:
     976           0 :         bp->b_resid = bp->b_bcount;
     977           0 :         return (-1);
     978           0 : }
     979             : 
     980             : /*
     981             :  * Disk error is the preface to plaintive error messages
     982             :  * about failing disk transfers.  It prints messages of the form
     983             : 
     984             : hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d)
     985             : 
     986             :  * if the offset of the error in the transfer and a disk label
     987             :  * are both available.  blkdone should be -1 if the position of the error
     988             :  * is unknown; the disklabel pointer may be null from drivers that have not
     989             :  * been converted to use them.  The message is printed with printf
     990             :  * if pri is LOG_PRINTF, otherwise it uses log at the specified priority.
     991             :  * The message should be completed (with at least a newline) with printf
     992             :  * or addlog, respectively.  There is no trailing space.
     993             :  */
     994             : void
     995           0 : diskerr(struct buf *bp, char *dname, char *what, int pri, int blkdone,
     996             :     struct disklabel *lp)
     997             : {
     998           0 :         int unit = DISKUNIT(bp->b_dev), part = DISKPART(bp->b_dev);
     999             :         int (*pr)(const char *, ...) __attribute__((__format__(__kprintf__,1,2)));
    1000           0 :         char partname = 'a' + part;
    1001             :         daddr_t sn;
    1002             : 
    1003           0 :         if (pri != LOG_PRINTF) {
    1004           0 :                 log(pri, "%s", "");
    1005             :                 pr = addlog;
    1006           0 :         } else
    1007             :                 pr = printf;
    1008           0 :         (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what,
    1009           0 :             bp->b_flags & B_READ ? "read" : "writ");
    1010           0 :         sn = bp->b_blkno;
    1011           0 :         if (bp->b_bcount <= DEV_BSIZE)
    1012           0 :                 (*pr)("%lld", (long long)sn);
    1013             :         else {
    1014           0 :                 if (blkdone >= 0) {
    1015           0 :                         sn += blkdone;
    1016           0 :                         (*pr)("%lld of ", (long long)sn);
    1017           0 :                 }
    1018           0 :                 (*pr)("%lld-%lld", (long long)bp->b_blkno,
    1019           0 :                     (long long)(bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE));
    1020             :         }
    1021           0 :         if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) {
    1022           0 :                 sn += DL_SECTOBLK(lp, DL_GETPOFFSET(&lp->d_partitions[part]));
    1023           0 :                 (*pr)(" (%s%d bn %lld; cn %lld", dname, unit, (long long)sn,
    1024           0 :                     (long long)(sn / DL_SECTOBLK(lp, lp->d_secpercyl)));
    1025           0 :                 sn %= DL_SECTOBLK(lp, lp->d_secpercyl);
    1026           0 :                 (*pr)(" tn %lld sn %lld)",
    1027           0 :                     (long long)(sn / DL_SECTOBLK(lp, lp->d_nsectors)),
    1028           0 :                     (long long)(sn % DL_SECTOBLK(lp, lp->d_nsectors)));
    1029           0 :         }
    1030           0 : }
    1031             : 
    1032             : /*
    1033             :  * Initialize the disklist.  Called by main() before autoconfiguration.
    1034             :  */
    1035             : void
    1036           0 : disk_init(void)
    1037             : {
    1038             : 
    1039           0 :         TAILQ_INIT(&disklist);
    1040           0 :         disk_count = disk_change = 0;
    1041           0 : }
    1042             : 
    1043             : int
    1044           0 : disk_construct(struct disk *diskp)
    1045             : {
    1046           0 :         rw_init_flags(&diskp->dk_lock, "dklk", RWL_IS_VNODE);
    1047           0 :         mtx_init(&diskp->dk_mtx, IPL_BIO);
    1048             : 
    1049           0 :         diskp->dk_flags |= DKF_CONSTRUCTED;
    1050             : 
    1051           0 :         return (0);
    1052             : }
    1053             : 
    1054             : /*
    1055             :  * Attach a disk.
    1056             :  */
    1057             : void
    1058           0 : disk_attach(struct device *dv, struct disk *diskp)
    1059             : {
    1060             :         int majdev;
    1061             : 
    1062           0 :         if (!ISSET(diskp->dk_flags, DKF_CONSTRUCTED))
    1063           0 :                 disk_construct(diskp);
    1064             : 
    1065             :         /*
    1066             :          * Allocate and initialize the disklabel structures.  Note that
    1067             :          * it's not safe to sleep here, since we're probably going to be
    1068             :          * called during autoconfiguration.
    1069             :          */
    1070           0 :         diskp->dk_label = malloc(sizeof(struct disklabel), M_DEVBUF,
    1071             :             M_NOWAIT|M_ZERO);
    1072           0 :         if (diskp->dk_label == NULL)
    1073           0 :                 panic("disk_attach: can't allocate storage for disklabel");
    1074             : 
    1075             :         /*
    1076             :          * Set the attached timestamp.
    1077             :          */
    1078           0 :         microuptime(&diskp->dk_attachtime);
    1079             : 
    1080             :         /*
    1081             :          * Link into the disklist.
    1082             :          */
    1083           0 :         TAILQ_INSERT_TAIL(&disklist, diskp, dk_link);
    1084           0 :         ++disk_count;
    1085           0 :         disk_change = 1;
    1086             : 
    1087             :         /*
    1088             :          * Store device structure and number for later use.
    1089             :          */
    1090           0 :         diskp->dk_device = dv;
    1091           0 :         diskp->dk_devno = NODEV;
    1092           0 :         if (dv != NULL) {
    1093           0 :                 majdev = findblkmajor(dv);
    1094           0 :                 if (majdev >= 0)
    1095           0 :                         diskp->dk_devno =
    1096           0 :                             MAKEDISKDEV(majdev, dv->dv_unit, RAW_PART);
    1097             : 
    1098           0 :                 if (diskp->dk_devno != NODEV) {
    1099             :                         struct disk_attach_task *dat;
    1100             : 
    1101           0 :                         dat = malloc(sizeof(*dat), M_TEMP, M_WAITOK);
    1102             : 
    1103             :                         /* XXX: Assumes dk is part of the device softc. */
    1104           0 :                         device_ref(dv);
    1105           0 :                         dat->dk = diskp;
    1106             : 
    1107           0 :                         task_set(&dat->task, disk_attach_callback, dat);
    1108           0 :                         task_add(systq, &dat->task);
    1109           0 :                 }
    1110             :         }
    1111             : 
    1112           0 :         if (softraid_disk_attach)
    1113           0 :                 softraid_disk_attach(diskp, 1);
    1114           0 : }
    1115             : 
    1116             : void
    1117           0 : disk_attach_callback(void *xdat)
    1118             : {
    1119           0 :         struct disk_attach_task *dat = xdat;
    1120           0 :         struct disk *dk = dat->dk;
    1121           0 :         struct disklabel dl;
    1122           0 :         char errbuf[100];
    1123             : 
    1124           0 :         free(dat, M_TEMP, sizeof(*dat));
    1125             : 
    1126           0 :         if (dk->dk_flags & (DKF_OPENED | DKF_NOLABELREAD))
    1127             :                 goto done;
    1128             : 
    1129             :         /* Read disklabel. */
    1130           0 :         if (disk_readlabel(&dl, dk->dk_devno, errbuf, sizeof(errbuf)) == NULL) {
    1131           0 :                 enqueue_randomness(dl.d_checksum);
    1132           0 :                 dk->dk_flags |= DKF_LABELVALID;
    1133           0 :         }
    1134             : 
    1135             : done:
    1136           0 :         dk->dk_flags |= DKF_OPENED;
    1137           0 :         device_unref(dk->dk_device);
    1138           0 :         wakeup(dk);
    1139           0 : }
    1140             : 
    1141             : /*
    1142             :  * Detach a disk.
    1143             :  */
    1144             : void
    1145           0 : disk_detach(struct disk *diskp)
    1146             : {
    1147             : 
    1148           0 :         if (softraid_disk_attach)
    1149           0 :                 softraid_disk_attach(diskp, -1);
    1150             : 
    1151             :         /*
    1152             :          * Free the space used by the disklabel structures.
    1153             :          */
    1154           0 :         free(diskp->dk_label, M_DEVBUF, sizeof(*diskp->dk_label));
    1155             : 
    1156             :         /*
    1157             :          * Remove from the disklist.
    1158             :          */
    1159           0 :         TAILQ_REMOVE(&disklist, diskp, dk_link);
    1160           0 :         disk_change = 1;
    1161           0 :         if (--disk_count < 0)
    1162           0 :                 panic("disk_detach: disk_count < 0");
    1163           0 : }
    1164             : 
    1165             : int
    1166           0 : disk_openpart(struct disk *dk, int part, int fmt, int haslabel)
    1167             : {
    1168           0 :         KASSERT(part >= 0 && part < MAXPARTITIONS);
    1169             : 
    1170             :         /* Unless opening the raw partition, check that the partition exists. */
    1171           0 :         if (part != RAW_PART && (!haslabel ||
    1172           0 :             part >= dk->dk_label->d_npartitions ||
    1173           0 :             dk->dk_label->d_partitions[part].p_fstype == FS_UNUSED))
    1174           0 :                 return (ENXIO);
    1175             : 
    1176             :         /* Ensure the partition doesn't get changed under our feet. */
    1177           0 :         switch (fmt) {
    1178             :         case S_IFCHR:
    1179           0 :                 dk->dk_copenmask |= (1 << part);
    1180           0 :                 break;
    1181             :         case S_IFBLK:
    1182           0 :                 dk->dk_bopenmask |= (1 << part);
    1183           0 :                 break;
    1184             :         }
    1185           0 :         dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
    1186             : 
    1187           0 :         return (0);
    1188           0 : }
    1189             : 
    1190             : void
    1191           0 : disk_closepart(struct disk *dk, int part, int fmt)
    1192             : {
    1193           0 :         KASSERT(part >= 0 && part < MAXPARTITIONS);
    1194             : 
    1195           0 :         switch (fmt) {
    1196             :         case S_IFCHR:
    1197           0 :                 dk->dk_copenmask &= ~(1 << part);
    1198           0 :                 break;
    1199             :         case S_IFBLK:
    1200           0 :                 dk->dk_bopenmask &= ~(1 << part);
    1201           0 :                 break;
    1202             :         }
    1203           0 :         dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
    1204           0 : }
    1205             : 
    1206             : void
    1207           0 : disk_gone(int (*open)(dev_t, int, int, struct proc *), int unit)
    1208             : {
    1209             :         int bmaj, cmaj, mn;
    1210             : 
    1211             :         /* Locate the lowest minor number to be detached. */
    1212           0 :         mn = DISKMINOR(unit, 0);
    1213             : 
    1214           0 :         for (bmaj = 0; bmaj < nblkdev; bmaj++)
    1215           0 :                 if (bdevsw[bmaj].d_open == open)
    1216           0 :                         vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK);
    1217           0 :         for (cmaj = 0; cmaj < nchrdev; cmaj++)
    1218           0 :                 if (cdevsw[cmaj].d_open == open)
    1219           0 :                         vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR);
    1220           0 : }
    1221             : 
    1222             : /*
    1223             :  * Increment a disk's busy counter.  If the counter is going from
    1224             :  * 0 to 1, set the timestamp.
    1225             :  */
    1226             : void
    1227           0 : disk_busy(struct disk *diskp)
    1228             : {
    1229             : 
    1230             :         /*
    1231             :          * XXX We'd like to use something as accurate as microtime(),
    1232             :          * but that doesn't depend on the system TOD clock.
    1233             :          */
    1234           0 :         mtx_enter(&diskp->dk_mtx);
    1235           0 :         if (diskp->dk_busy++ == 0)
    1236           0 :                 microuptime(&diskp->dk_timestamp);
    1237           0 :         mtx_leave(&diskp->dk_mtx);
    1238           0 : }
    1239             : 
    1240             : /*
    1241             :  * Decrement a disk's busy counter, increment the byte count, total busy
    1242             :  * time, and reset the timestamp.
    1243             :  */
    1244             : void
    1245           0 : disk_unbusy(struct disk *diskp, long bcount, daddr_t blkno, int read)
    1246             : {
    1247           0 :         struct timeval dv_time, diff_time;
    1248             : 
    1249           0 :         mtx_enter(&diskp->dk_mtx);
    1250             : 
    1251           0 :         if (diskp->dk_busy-- == 0)
    1252           0 :                 printf("disk_unbusy: %s: dk_busy < 0\n", diskp->dk_name);
    1253             : 
    1254           0 :         microuptime(&dv_time);
    1255             : 
    1256           0 :         timersub(&dv_time, &diskp->dk_timestamp, &diff_time);
    1257           0 :         timeradd(&diskp->dk_time, &diff_time, &diskp->dk_time);
    1258             : 
    1259           0 :         diskp->dk_timestamp = dv_time;
    1260           0 :         if (bcount > 0) {
    1261           0 :                 if (read) {
    1262           0 :                         diskp->dk_rbytes += bcount;
    1263           0 :                         diskp->dk_rxfer++;
    1264           0 :                 } else {
    1265           0 :                         diskp->dk_wbytes += bcount;
    1266           0 :                         diskp->dk_wxfer++;
    1267             :                 }
    1268             :         } else
    1269           0 :                 diskp->dk_seek++;
    1270             : 
    1271           0 :         mtx_leave(&diskp->dk_mtx);
    1272             : 
    1273           0 :         enqueue_randomness(bcount ^ diff_time.tv_usec ^
    1274           0 :             (blkno >> 32) ^ (blkno & 0xffffffff));
    1275           0 : }
    1276             : 
    1277             : int
    1278           0 : disk_lock(struct disk *dk)
    1279             : {
    1280           0 :         return (rw_enter(&dk->dk_lock, RW_WRITE|RW_INTR));
    1281             : }
    1282             : 
    1283             : void
    1284           0 : disk_lock_nointr(struct disk *dk)
    1285             : {
    1286           0 :         rw_enter_write(&dk->dk_lock);
    1287           0 : }
    1288             : 
    1289             : void
    1290           0 : disk_unlock(struct disk *dk)
    1291             : {
    1292           0 :         rw_exit_write(&dk->dk_lock);
    1293           0 : }
    1294             : 
    1295             : int
    1296           0 : dk_mountroot(void)
    1297             : {
    1298           0 :         char errbuf[100];
    1299           0 :         int part = DISKPART(rootdev);
    1300             :         int (*mountrootfn)(void);
    1301           0 :         struct disklabel dl;
    1302             :         char *error;
    1303             : 
    1304           0 :         error = disk_readlabel(&dl, rootdev, errbuf, sizeof(errbuf));
    1305           0 :         if (error)
    1306           0 :                 panic("%s", error);
    1307             : 
    1308           0 :         if (DL_GETPSIZE(&dl.d_partitions[part]) == 0)
    1309           0 :                 panic("root filesystem has size 0");
    1310           0 :         switch (dl.d_partitions[part].p_fstype) {
    1311             : #ifdef EXT2FS
    1312             :         case FS_EXT2FS:
    1313             :                 {
    1314             :                 extern int ext2fs_mountroot(void);
    1315             :                 mountrootfn = ext2fs_mountroot;
    1316             :                 }
    1317           0 :                 break;
    1318             : #endif
    1319             : #ifdef FFS
    1320             :         case FS_BSDFFS:
    1321             :                 {
    1322             :                 extern int ffs_mountroot(void);
    1323             :                 mountrootfn = ffs_mountroot;
    1324             :                 }
    1325           0 :                 break;
    1326             : #endif
    1327             : #ifdef CD9660
    1328             :         case FS_ISO9660:
    1329             :                 {
    1330             :                 extern int cd9660_mountroot(void);
    1331             :                 mountrootfn = cd9660_mountroot;
    1332             :                 }
    1333           0 :                 break;
    1334             : #endif
    1335             :         default:
    1336             : #ifdef FFS
    1337             :                 {
    1338             :                 extern int ffs_mountroot(void);
    1339             : 
    1340           0 :                 printf("filesystem type %d not known.. assuming ffs\n",
    1341             :                     dl.d_partitions[part].p_fstype);
    1342             :                 mountrootfn = ffs_mountroot;
    1343             :                 }
    1344             : #else
    1345             :                 panic("disk 0x%x filesystem type %d not known",
    1346             :                     rootdev, dl.d_partitions[part].p_fstype);
    1347             : #endif
    1348           0 :         }
    1349           0 :         return (*mountrootfn)();
    1350           0 : }
    1351             : 
    1352             : struct device *
    1353           0 : getdisk(char *str, int len, int defpart, dev_t *devp)
    1354             : {
    1355             :         struct device *dv;
    1356             : 
    1357           0 :         if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
    1358           0 :                 printf("use one of: exit");
    1359           0 :                 TAILQ_FOREACH(dv, &alldevs, dv_list) {
    1360           0 :                         if (dv->dv_class == DV_DISK)
    1361           0 :                                 printf(" %s[a-p]", dv->dv_xname);
    1362             : #if defined(NFSCLIENT)
    1363           0 :                         if (dv->dv_class == DV_IFNET)
    1364           0 :                                 printf(" %s", dv->dv_xname);
    1365             : #endif
    1366             :                 }
    1367           0 :                 printf("\n");
    1368           0 :         }
    1369           0 :         return (dv);
    1370             : }
    1371             : 
    1372             : struct device *
    1373           0 : parsedisk(char *str, int len, int defpart, dev_t *devp)
    1374             : {
    1375             :         struct device *dv;
    1376             :         int majdev, part = defpart;
    1377             :         char c;
    1378             : 
    1379           0 :         if (len == 0)
    1380           0 :                 return (NULL);
    1381           0 :         c = str[len-1];
    1382           0 :         if (c >= 'a' && (c - 'a') < MAXPARTITIONS) {
    1383             :                 part = c - 'a';
    1384             :                 len -= 1;
    1385           0 :         }
    1386             : 
    1387           0 :         TAILQ_FOREACH(dv, &alldevs, dv_list) {
    1388           0 :                 if (dv->dv_class == DV_DISK &&
    1389           0 :                     strncmp(str, dv->dv_xname, len) == 0 &&
    1390           0 :                     dv->dv_xname[len] == '\0') {
    1391           0 :                         majdev = findblkmajor(dv);
    1392           0 :                         if (majdev < 0)
    1393           0 :                                 return NULL;
    1394           0 :                         *devp = MAKEDISKDEV(majdev, dv->dv_unit, part);
    1395           0 :                         break;
    1396             :                 }
    1397             : #if defined(NFSCLIENT)
    1398           0 :                 if (dv->dv_class == DV_IFNET &&
    1399           0 :                     strncmp(str, dv->dv_xname, len) == 0 &&
    1400           0 :                     dv->dv_xname[len] == '\0') {
    1401           0 :                         *devp = NODEV;
    1402           0 :                         break;
    1403             :                 }
    1404             : #endif
    1405             :         }
    1406             : 
    1407           0 :         return (dv);
    1408           0 : }
    1409             : 
    1410             : void
    1411           0 : setroot(struct device *bootdv, int part, int exitflags)
    1412             : {
    1413             :         int majdev, unit, len, s, slept = 0;
    1414             :         struct swdevt *swp;
    1415             :         struct device *rootdv, *dv;
    1416           0 :         dev_t nrootdev, nswapdev = NODEV, temp = NODEV;
    1417             :         struct ifnet *ifp = NULL;
    1418             :         struct disk *dk;
    1419           0 :         char buf[128];
    1420             : #if defined(NFSCLIENT)
    1421             :         extern char *nfsbootdevname;
    1422             : #endif
    1423             : 
    1424             :         /* Ensure that all disk attach callbacks have completed. */
    1425           0 :         do {
    1426           0 :                 TAILQ_FOREACH(dk, &disklist, dk_link) {
    1427           0 :                         if (dk->dk_devno != NODEV &&
    1428           0 :                             (dk->dk_flags & DKF_OPENED) == 0) {
    1429           0 :                                 tsleep(dk, 0, "dkopen", hz);
    1430           0 :                                 slept++;
    1431           0 :                                 break;
    1432             :                         }
    1433             :                 }
    1434           0 :         } while (dk != NULL && slept < 5);
    1435             : 
    1436           0 :         if (slept == 5) {
    1437           0 :                 printf("disklabels not read:");
    1438           0 :                 TAILQ_FOREACH(dk, &disklist, dk_link)
    1439           0 :                         if (dk->dk_devno != NODEV &&
    1440           0 :                             (dk->dk_flags & DKF_OPENED) == 0)
    1441           0 :                                 printf(" %s", dk->dk_name);
    1442           0 :                 printf("\n");
    1443           0 :         }
    1444             : 
    1445           0 :         if (duid_iszero(bootduid)) {
    1446             :                 /* Locate DUID for boot disk since it was not provided. */
    1447           0 :                 TAILQ_FOREACH(dk, &disklist, dk_link)
    1448           0 :                         if (dk->dk_device == bootdv)
    1449             :                                 break;
    1450           0 :                 if (dk && (dk->dk_flags & DKF_LABELVALID))
    1451           0 :                         bcopy(dk->dk_label->d_uid, bootduid, sizeof(bootduid));
    1452           0 :         } else if (bootdv == NULL) {
    1453             :                 /* Locate boot disk based on the provided DUID. */
    1454           0 :                 TAILQ_FOREACH(dk, &disklist, dk_link)
    1455           0 :                         if (duid_equal(dk->dk_label->d_uid, bootduid))
    1456             :                                 break;
    1457           0 :                 if (dk && (dk->dk_flags & DKF_LABELVALID))
    1458           0 :                         bootdv = dk->dk_device;
    1459             :         }
    1460           0 :         bcopy(bootduid, rootduid, sizeof(rootduid));
    1461             : 
    1462             : #if NSOFTRAID > 0
    1463           0 :         sr_map_root();
    1464             : #endif
    1465             : 
    1466             :         /*
    1467             :          * If `swap generic' and we couldn't determine boot device,
    1468             :          * ask the user.
    1469             :          */
    1470             :         dk = NULL;
    1471           0 :         if (mountroot == NULL && bootdv == NULL)
    1472           0 :                 boothowto |= RB_ASKNAME;
    1473           0 :         if (boothowto & RB_ASKNAME) {
    1474           0 :                 while (1) {
    1475           0 :                         printf("root device");
    1476           0 :                         if (bootdv != NULL) {
    1477           0 :                                 printf(" (default %s", bootdv->dv_xname);
    1478           0 :                                 if (bootdv->dv_class == DV_DISK)
    1479           0 :                                         printf("%c", 'a' + part);
    1480           0 :                                 printf(")");
    1481           0 :                         }
    1482           0 :                         printf(": ");
    1483           0 :                         s = splhigh();
    1484           0 :                         cnpollc(1);
    1485           0 :                         len = getsn(buf, sizeof(buf));
    1486           0 :                         cnpollc(0);
    1487           0 :                         splx(s);
    1488           0 :                         if (strcmp(buf, "exit") == 0)
    1489           0 :                                 reboot(exitflags);
    1490           0 :                         if (len == 0 && bootdv != NULL) {
    1491           0 :                                 strlcpy(buf, bootdv->dv_xname, sizeof buf);
    1492           0 :                                 len = strlen(buf);
    1493           0 :                         }
    1494           0 :                         if (len > 0 && buf[len - 1] == '*') {
    1495           0 :                                 buf[--len] = '\0';
    1496           0 :                                 dv = getdisk(buf, len, part, &nrootdev);
    1497           0 :                                 if (dv != NULL) {
    1498             :                                         rootdv = dv;
    1499           0 :                                         nswapdev = nrootdev;
    1500           0 :                                         goto gotswap;
    1501             :                                 }
    1502             :                         }
    1503           0 :                         dv = getdisk(buf, len, part, &nrootdev);
    1504           0 :                         if (dv != NULL) {
    1505             :                                 rootdv = dv;
    1506             :                                 break;
    1507             :                         }
    1508             :                 }
    1509             : 
    1510           0 :                 if (rootdv->dv_class == DV_IFNET)
    1511             :                         goto gotswap;
    1512             : 
    1513             :                 /* try to build swap device out of new root device */
    1514           0 :                 while (1) {
    1515           0 :                         printf("swap device");
    1516           0 :                         if (rootdv != NULL)
    1517           0 :                                 printf(" (default %s%s)", rootdv->dv_xname,
    1518           0 :                                     rootdv->dv_class == DV_DISK ? "b" : "");
    1519           0 :                         printf(": ");
    1520           0 :                         s = splhigh();
    1521           0 :                         cnpollc(1);
    1522           0 :                         len = getsn(buf, sizeof(buf));
    1523           0 :                         cnpollc(0);
    1524           0 :                         splx(s);
    1525           0 :                         if (strcmp(buf, "exit") == 0)
    1526           0 :                                 reboot(exitflags);
    1527           0 :                         if (len == 0 && rootdv != NULL) {
    1528           0 :                                 switch (rootdv->dv_class) {
    1529             :                                 case DV_IFNET:
    1530           0 :                                         nswapdev = NODEV;
    1531           0 :                                         break;
    1532             :                                 case DV_DISK:
    1533           0 :                                         nswapdev = MAKEDISKDEV(major(nrootdev),
    1534             :                                             DISKUNIT(nrootdev), 1);
    1535           0 :                                         if (nswapdev == nrootdev)
    1536           0 :                                                 continue;
    1537             :                                         break;
    1538             :                                 default:
    1539             :                                         break;
    1540             :                                 }
    1541             :                                 break;
    1542             :                         }
    1543           0 :                         dv = getdisk(buf, len, 1, &nswapdev);
    1544           0 :                         if (dv) {
    1545           0 :                                 if (dv->dv_class == DV_IFNET)
    1546           0 :                                         nswapdev = NODEV;
    1547           0 :                                 if (nswapdev == nrootdev)
    1548           0 :                                         continue;
    1549             :                                 break;
    1550             :                         }
    1551             :                 }
    1552             : gotswap:
    1553           0 :                 rootdev = nrootdev;
    1554           0 :                 dumpdev = nswapdev;
    1555           0 :                 swdevt[0].sw_dev = nswapdev;
    1556           0 :                 swdevt[1].sw_dev = NODEV;
    1557             : #if defined(NFSCLIENT)
    1558           0 :         } else if (mountroot == nfs_mountroot) {
    1559             :                 rootdv = bootdv;
    1560           0 :                 rootdev = dumpdev = swapdev = NODEV;
    1561             : #endif
    1562           0 :         } else if (mountroot == NULL && rootdev == NODEV) {
    1563             :                 /*
    1564             :                  * `swap generic'
    1565             :                  */
    1566             :                 rootdv = bootdv;
    1567             : 
    1568           0 :                 if (bootdv->dv_class == DV_DISK) {
    1569           0 :                         if (!duid_iszero(rootduid)) {
    1570           0 :                                 TAILQ_FOREACH(dk, &disklist, dk_link)
    1571           0 :                                         if ((dk->dk_flags & DKF_LABELVALID) &&
    1572           0 :                                             dk->dk_label && duid_equal(
    1573           0 :                                             dk->dk_label->d_uid, rootduid))
    1574             :                                                 break;
    1575           0 :                                 if (dk == NULL)
    1576           0 :                                         panic("root device (%s) not found",
    1577           0 :                                             duid_format(rootduid));
    1578           0 :                                 rootdv = dk->dk_device;
    1579           0 :                         }
    1580             :                 }
    1581             : 
    1582           0 :                 majdev = findblkmajor(rootdv);
    1583           0 :                 if (majdev >= 0) {
    1584             :                         /*
    1585             :                          * Root and swap are on the disk.
    1586             :                          * Assume swap is on partition b.
    1587             :                          */
    1588           0 :                         rootdev = MAKEDISKDEV(majdev, rootdv->dv_unit, part);
    1589           0 :                         nswapdev = MAKEDISKDEV(majdev, rootdv->dv_unit, 1);
    1590           0 :                 } else {
    1591             :                         /*
    1592             :                          * Root and swap are on a net.
    1593             :                          */
    1594           0 :                         nswapdev = NODEV;
    1595             :                 }
    1596           0 :                 dumpdev = nswapdev;
    1597           0 :                 swdevt[0].sw_dev = nswapdev;
    1598             :                 /* swdevt[1].sw_dev = NODEV; */
    1599           0 :         } else {
    1600             :                 /* Completely pre-configured, but we want rootdv .. */
    1601           0 :                 majdev = major(rootdev);
    1602           0 :                 if (findblkname(majdev) == NULL)
    1603           0 :                         return;
    1604           0 :                 unit = DISKUNIT(rootdev);
    1605           0 :                 part = DISKPART(rootdev);
    1606           0 :                 snprintf(buf, sizeof buf, "%s%d%c",
    1607           0 :                     findblkname(majdev), unit, 'a' + part);
    1608           0 :                 rootdv = parsedisk(buf, strlen(buf), 0, &nrootdev);
    1609           0 :                 if (rootdv == NULL)
    1610           0 :                         panic("root device (%s) not found", buf);
    1611             :         }
    1612             : 
    1613           0 :         if (rootdv && rootdv == bootdv && rootdv->dv_class == DV_IFNET)
    1614           0 :                 ifp = ifunit(rootdv->dv_xname);
    1615           0 :         else if (bootdv && bootdv->dv_class == DV_IFNET)
    1616           0 :                 ifp = ifunit(bootdv->dv_xname);
    1617             : 
    1618           0 :         if (ifp)
    1619           0 :                 if_addgroup(ifp, "netboot");
    1620             : 
    1621           0 :         switch (rootdv->dv_class) {
    1622             : #if defined(NFSCLIENT)
    1623             :         case DV_IFNET:
    1624           0 :                 mountroot = nfs_mountroot;
    1625           0 :                 nfsbootdevname = rootdv->dv_xname;
    1626           0 :                 return;
    1627             : #endif
    1628             :         case DV_DISK:
    1629           0 :                 mountroot = dk_mountroot;
    1630           0 :                 part = DISKPART(rootdev);
    1631             :                 break;
    1632             :         default:
    1633           0 :                 printf("can't figure root, hope your kernel is right\n");
    1634           0 :                 return;
    1635             :         }
    1636             : 
    1637           0 :         printf("root on %s%c", rootdv->dv_xname, 'a' + part);
    1638             : 
    1639           0 :         if (dk && dk->dk_device == rootdv)
    1640           0 :                 printf(" (%s.%c)", duid_format(rootduid), 'a' + part);
    1641             : 
    1642             :         /*
    1643             :          * Make the swap partition on the root drive the primary swap.
    1644             :          */
    1645           0 :         for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
    1646           0 :                 if (major(rootdev) == major(swp->sw_dev) &&
    1647           0 :                     DISKUNIT(rootdev) == DISKUNIT(swp->sw_dev)) {
    1648           0 :                         temp = swdevt[0].sw_dev;
    1649           0 :                         swdevt[0].sw_dev = swp->sw_dev;
    1650           0 :                         swp->sw_dev = temp;
    1651           0 :                         break;
    1652             :                 }
    1653             :         }
    1654           0 :         if (swp->sw_dev != NODEV) {
    1655             :                 /*
    1656             :                  * If dumpdev was the same as the old primary swap device,
    1657             :                  * move it to the new primary swap device.
    1658             :                  */
    1659           0 :                 if (temp == dumpdev)
    1660           0 :                         dumpdev = swdevt[0].sw_dev;
    1661             :         }
    1662           0 :         if (swdevt[0].sw_dev != NODEV)
    1663           0 :                 printf(" swap on %s%d%c", findblkname(major(swdevt[0].sw_dev)),
    1664           0 :                     DISKUNIT(swdevt[0].sw_dev),
    1665           0 :                     'a' + DISKPART(swdevt[0].sw_dev));
    1666           0 :         if (dumpdev != NODEV)
    1667           0 :                 printf(" dump on %s%d%c", findblkname(major(dumpdev)),
    1668           0 :                     DISKUNIT(dumpdev), 'a' + DISKPART(dumpdev));
    1669           0 :         printf("\n");
    1670           0 : }
    1671             : 
    1672             : extern struct nam2blk nam2blk[];
    1673             : 
    1674             : int
    1675           0 : findblkmajor(struct device *dv)
    1676             : {
    1677           0 :         char buf[16], *p;
    1678             :         int i;
    1679             : 
    1680           0 :         if (strlcpy(buf, dv->dv_xname, sizeof buf) >= sizeof buf)
    1681           0 :                 return (-1);
    1682           0 :         for (p = buf; *p; p++)
    1683           0 :                 if (*p >= '0' && *p <= '9')
    1684           0 :                         *p = '\0';
    1685             : 
    1686           0 :         for (i = 0; nam2blk[i].name; i++)
    1687           0 :                 if (!strcmp(buf, nam2blk[i].name))
    1688           0 :                         return (nam2blk[i].maj);
    1689           0 :         return (-1);
    1690           0 : }
    1691             : 
    1692             : char *
    1693           0 : findblkname(int maj)
    1694             : {
    1695             :         int i;
    1696             : 
    1697           0 :         for (i = 0; nam2blk[i].name; i++)
    1698           0 :                 if (nam2blk[i].maj == maj)
    1699           0 :                         return (nam2blk[i].name);
    1700           0 :         return (NULL);
    1701           0 : }
    1702             : 
    1703             : char *
    1704           0 : disk_readlabel(struct disklabel *dl, dev_t dev, char *errbuf, size_t errsize)
    1705             : {
    1706           0 :         struct vnode *vn;
    1707             :         dev_t chrdev, rawdev;
    1708             :         int error;
    1709             : 
    1710           0 :         chrdev = blktochr(dev);
    1711           0 :         rawdev = MAKEDISKDEV(major(chrdev), DISKUNIT(chrdev), RAW_PART);
    1712             : 
    1713             : #ifdef DEBUG
    1714             :         printf("dev=0x%x chrdev=0x%x rawdev=0x%x\n", dev, chrdev, rawdev);
    1715             : #endif
    1716             : 
    1717           0 :         if (cdevvp(rawdev, &vn)) {
    1718           0 :                 snprintf(errbuf, errsize,
    1719             :                     "cannot obtain vnode for 0x%x/0x%x", dev, rawdev);
    1720           0 :                 return (errbuf);
    1721             :         }
    1722             : 
    1723           0 :         error = VOP_OPEN(vn, FREAD, NOCRED, curproc);
    1724           0 :         if (error) {
    1725           0 :                 snprintf(errbuf, errsize,
    1726             :                     "cannot open disk, 0x%x/0x%x, error %d",
    1727             :                     dev, rawdev, error);
    1728           0 :                 goto done;
    1729             :         }
    1730             : 
    1731           0 :         error = VOP_IOCTL(vn, DIOCGDINFO, (caddr_t)dl, FREAD, NOCRED, curproc);
    1732           0 :         if (error) {
    1733           0 :                 snprintf(errbuf, errsize,
    1734             :                     "cannot read disk label, 0x%x/0x%x, error %d",
    1735             :                     dev, rawdev, error);
    1736           0 :         }
    1737             : done:
    1738           0 :         VOP_CLOSE(vn, FREAD, NOCRED, curproc);
    1739           0 :         vput(vn);
    1740           0 :         if (error)
    1741           0 :                 return (errbuf);
    1742           0 :         return (NULL);
    1743           0 : }
    1744             : 
    1745             : int
    1746           0 : disk_map(char *path, char *mappath, int size, int flags)
    1747             : {
    1748             :         struct disk *dk, *mdk;
    1749           0 :         u_char uid[8];
    1750             :         char c, part;
    1751             :         int i;
    1752             : 
    1753             :         /*
    1754             :          * Attempt to map a request for a disklabel UID to the correct device.
    1755             :          * We should be supplied with a disklabel UID which has the following
    1756             :          * format:
    1757             :          *
    1758             :          * [disklabel uid] . [partition]
    1759             :          *
    1760             :          * Alternatively, if the DM_OPENPART flag is set the disklabel UID can
    1761             :          * based passed on its own.
    1762             :          */
    1763             : 
    1764           0 :         if (strchr(path, '/') != NULL)
    1765           0 :                 return -1;
    1766             : 
    1767             :         /* Verify that the device name is properly formed. */
    1768           0 :         if (!((strlen(path) == 16 && (flags & DM_OPENPART)) ||
    1769           0 :             (strlen(path) == 18 && path[16] == '.')))
    1770           0 :                 return -1;
    1771             : 
    1772             :         /* Get partition. */
    1773           0 :         if (flags & DM_OPENPART)
    1774           0 :                 part = 'a' + RAW_PART;
    1775             :         else
    1776           0 :                 part = path[17];
    1777             : 
    1778           0 :         if (part < 'a' || part >= 'a' + MAXPARTITIONS)
    1779           0 :                 return -1;
    1780             : 
    1781             :         /* Derive label UID. */
    1782           0 :         memset(uid, 0, sizeof(uid));
    1783           0 :         for (i = 0; i < 16; i++) {
    1784           0 :                 c = path[i];
    1785           0 :                 if (c >= '0' && c <= '9')
    1786           0 :                         c -= '0';
    1787           0 :                 else if (c >= 'a' && c <= 'f')
    1788           0 :                         c -= ('a' - 10);
    1789             :                 else
    1790           0 :                         return -1;
    1791             : 
    1792           0 :                 uid[i / 2] <<= 4;
    1793           0 :                 uid[i / 2] |= c & 0xf;
    1794             :         }
    1795             : 
    1796             :         mdk = NULL;
    1797           0 :         TAILQ_FOREACH(dk, &disklist, dk_link) {
    1798           0 :                 if ((dk->dk_flags & DKF_LABELVALID) && dk->dk_label &&
    1799           0 :                     memcmp(dk->dk_label->d_uid, uid,
    1800           0 :                     sizeof(dk->dk_label->d_uid)) == 0) {
    1801             :                         /* Fail if there are duplicate UIDs! */
    1802           0 :                         if (mdk != NULL)
    1803           0 :                                 return -1;
    1804             :                         mdk = dk;
    1805           0 :                 }
    1806             :         }
    1807             : 
    1808           0 :         if (mdk == NULL || mdk->dk_name == NULL)
    1809           0 :                 return -1;
    1810             : 
    1811           0 :         snprintf(mappath, size, "/dev/%s%s%c",
    1812           0 :             (flags & DM_OPENBLCK) ? "" : "r", mdk->dk_name, part);
    1813             : 
    1814           0 :         return 0;
    1815           0 : }
    1816             : 
    1817             : /*
    1818             :  * Lookup a disk device and verify that it has completed attaching.
    1819             :  */
    1820             : struct device *
    1821           0 : disk_lookup(struct cfdriver *cd, int unit)
    1822             : {
    1823             :         struct device *dv;
    1824             :         struct disk *dk;
    1825             : 
    1826           0 :         dv = device_lookup(cd, unit);
    1827           0 :         if (dv == NULL)
    1828           0 :                 return (NULL);
    1829             : 
    1830           0 :         TAILQ_FOREACH(dk, &disklist, dk_link)
    1831           0 :                 if (dk->dk_device == dv)
    1832             :                         break;
    1833             : 
    1834           0 :         if (dk == NULL) {
    1835           0 :                 device_unref(dv);
    1836           0 :                 return (NULL);
    1837             :         }
    1838             : 
    1839           0 :         return (dv);
    1840           0 : }
    1841             : 
    1842             : int
    1843           0 : duid_equal(u_char *duid1, u_char *duid2)
    1844             : {
    1845           0 :         return (memcmp(duid1, duid2, DUID_SIZE) == 0);
    1846             : }
    1847             : 
    1848             : int
    1849           0 : duid_iszero(u_char *duid)
    1850             : {
    1851           0 :         u_char zeroduid[DUID_SIZE];
    1852             : 
    1853           0 :         memset(zeroduid, 0, sizeof(zeroduid));
    1854             : 
    1855           0 :         return (duid_equal(duid, zeroduid));
    1856           0 : }
    1857             : 
    1858             : const char *
    1859           0 : duid_format(u_char *duid)
    1860             : {
    1861             :         static char duid_str[17];
    1862             : 
    1863           0 :         snprintf(duid_str, sizeof(duid_str),
    1864             :             "%02x%02x%02x%02x%02x%02x%02x%02x",
    1865           0 :             duid[0], duid[1], duid[2], duid[3],
    1866           0 :             duid[4], duid[5], duid[6], duid[7]);
    1867             : 
    1868           0 :         return (duid_str);
    1869             : }

Generated by: LCOV version 1.13