1: /*
   2:  * Copyright (c) 1982, 1986, 1988, 1993
   3:  *	The Regents of the University of California.  All rights reserved.
   4:  * (c) UNIX System Laboratories, Inc.
   5:  * All or some portions of this file are derived from material licensed
   6:  * to the University of California by American Telephone and Telegraph
   7:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   8:  * the permission of UNIX System Laboratories, Inc.
   9:  *
  10:  * Redistribution and use in source and binary forms, with or without
  11:  * modification, are permitted provided that the following conditions
  12:  * are met:
  13:  * 1. Redistributions of source code must retain the above copyright
  14:  *    notice, this list of conditions and the following disclaimer.
  15:  * 2. Redistributions in binary form must reproduce the above copyright
  16:  *    notice, this list of conditions and the following disclaimer in the
  17:  *    documentation and/or other materials provided with the distribution.
  18:  * 3. All advertising materials mentioning features or use of this software
  19:  *    must display the following acknowledgement:
  20:  *	This product includes software developed by the University of
  21:  *	California, Berkeley and its contributors.
  22:  * 4. 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.5 (2.11BSD GTE) 1998/4/3
  39:  */
  40: 
  41: #include <errno.h>
  42: #include <syslog.h>
  43: #include <sys/param.h>
  44: #include <sys/user.h>
  45: #include <sys/systm.h>
  46: #include <machine/seg.h>
  47: #include <sys/buf.h>
  48: #include <sys/file.h>
  49: #include <sys/ioctl.h>
  50: #include <sys/disklabel.h>
  51: #include <sys/disk.h>
  52: 
  53: /*
  54:  * Attempt to read a disk label from a device using the indicated stategy
  55:  * routine.  The label must be partly set up before this: secpercyl and
  56:  * anything required in the strategy routine (e.g., sector size) must be
  57:  * filled in before calling us.  Returns NULL on success and an error
  58:  * string on failure.
  59:  */
  60: char *
  61: readdisklabel(dev, strat, lp)
  62:     dev_t dev;
  63:     int (*strat)();
  64:     register struct disklabel *lp;
  65:     {
  66:     register struct buf *bp;
  67:     struct disklabel *dlp;
  68:     char *msg = NULL;
  69: 
  70:     if  (lp->d_secperunit == 0)
  71:         lp->d_secperunit = 0x1fffffffL;
  72:     lp->d_npartitions = 1;
  73:     if  (lp->d_partitions[0].p_size == 0)
  74:         lp->d_partitions[0].p_size = 0x1fffffffL;
  75:     lp->d_partitions[0].p_offset = 0;
  76: 
  77:     bp = geteblk();
  78:     bp->b_dev = dev;
  79:     bp->b_blkno = LABELSECTOR;
  80:     bp->b_bcount = lp->d_secsize;   /* Probably should wire this to 512 */
  81:     bp->b_flags = B_BUSY | B_READ;
  82:     bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
  83:     (*strat)(bp);
  84:     biowait(bp);
  85:     if  (u.u_error)
  86:         msg = "I/O error";
  87:     else
  88:         {
  89:         dlp = (struct disklabel *)mapin(bp);
  90:         if  (dlp->d_magic != DISKMAGIC ||
  91:                 dlp->d_magic2 != DISKMAGIC)
  92:             {
  93:             if  (msg == NULL)
  94:                 msg = "no disk label";
  95:             }
  96:         else if (dlp->d_npartitions > MAXPARTITIONS || dkcksum(dlp))
  97:             msg = "disk label corrupted";
  98:         else
  99:             bcopy(dlp, lp, sizeof (struct disklabel));
 100:         mapout(bp);
 101:         }
 102:     bp->b_flags = B_INVAL | B_AGE;
 103:     brelse(bp);
 104:     return(msg);
 105:     }
 106: 
 107: /*
 108:  * Check new disk label for sensibility before setting it.  'olp' must point
 109:  * to a kernel resident (or mapped in) label.  'nlp' points to the new label
 110:  * usually present on the stack (having been passed in via ioctl from an
 111:  * application).
 112:  */
 113: int
 114: setdisklabel(olp, nlp, openmask)
 115:     struct disklabel *olp;
 116:     register struct disklabel *nlp;
 117:     u_short openmask;
 118: {
 119:     int i;
 120:     register struct partition *opp, *npp;
 121: 
 122:     if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
 123:         dkcksum(nlp) != 0)
 124:         return (EINVAL);
 125:     while ((i = ffs((long)openmask)) != 0) {
 126:         i--;
 127:         openmask &= ~(1 << i);
 128:         if (nlp->d_npartitions <= i)
 129:             return (EBUSY);
 130:         opp = &olp->d_partitions[i];
 131:         npp = &nlp->d_partitions[i];
 132:         if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
 133:             return (EBUSY);
 134:         /*
 135: 		 * Copy internally-set partition information
 136: 		 * if new label doesn't include it.		XXX
 137: 		 */
 138:         if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
 139:             npp->p_fstype = opp->p_fstype;
 140:             npp->p_fsize = opp->p_fsize;
 141:             npp->p_frag = opp->p_frag;
 142:         }
 143:     }
 144:     nlp->d_checksum = 0;
 145:     nlp->d_checksum = dkcksum(nlp);
 146:     bcopy(nlp, olp, sizeof (struct disklabel));
 147:     return (0);
 148: }
 149: 
 150: /*
 151:  * Write disk label back to device after modification.
 152:  */
 153: int
 154: writedisklabel(dev, strat, lp)
 155:     dev_t dev;
 156:     int (*strat)();
 157:     register struct disklabel *lp;
 158: {
 159:     struct buf *bp;
 160:     struct disklabel *dlp;
 161:     int labelpart;
 162:     int error = 0;
 163: 
 164:     labelpart = dkpart(dev);
 165:     if (lp->d_partitions[labelpart].p_offset != 0) {
 166:         if (lp->d_partitions[0].p_offset != 0)
 167:             return (EXDEV);         /* not quite right */
 168:         labelpart = 0;
 169:     }
 170:     bp = geteblk();
 171:     bp->b_dev = makedev(major(dev), dkminor(dkunit(dev), labelpart));
 172:     bp->b_blkno = LABELSECTOR;
 173:     bp->b_bcount = lp->d_secsize;   /* probably should wire to 512 */
 174:     bp->b_flags = B_READ;
 175:     (*strat)(bp);
 176:     biowait(bp);
 177:     if (u.u_error)
 178:         goto done;
 179:     dlp = (struct disklabel *)mapin(bp);
 180:     if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
 181:         dkcksum(dlp) == 0) {
 182:         bcopy(lp, dlp, sizeof (struct disklabel));
 183:         mapout(bp);
 184:         bp->b_flags = B_WRITE;
 185:         (*strat)(bp);
 186:         biowait(bp);
 187:         error = u.u_error;
 188:     } else {
 189:         error = ESRCH;
 190:         mapout(bp);
 191:     }
 192: done:
 193:     brelse(bp);
 194:     return(error);
 195: }
 196: 
 197: /*
 198:  * Compute checksum for disk label.
 199:  */
 200: dkcksum(lp)
 201:     struct disklabel *lp;
 202: {
 203:     register u_short *start, *end;
 204:     register u_short sum = 0;
 205: 
 206:     start = (u_short *)lp;
 207:     end = (u_short *)&lp->d_partitions[lp->d_npartitions];
 208:     while (start < end)
 209:         sum ^= *start++;
 210:     return (sum);
 211: }
 212: 
 213: /*
 214:  * This is new for 2.11BSD.  It is a common routine that checks for
 215:  * opening a partition that overlaps other currently open partitions.
 216:  *
 217:  * NOTE: if 'c' is not the entire drive (as is the case with the old,
 218:  * nonstandard, haphazard and overlapping partition tables) the warning
 219:  * message will be erroneously issued in some valid situations.
 220: */
 221: 
 222: #define RAWPART 2   /* 'c' */  /* XXX */
 223: 
 224: dkoverlapchk(openmask, dev, label, name)
 225:     int openmask;
 226:     dev_t   dev;
 227:     memaddr label;
 228:     char    *name;
 229:     {
 230:     int unit = dkunit(dev);
 231:     int part = dkpart(dev);
 232:     int partmask = 1 << part;
 233:     int i;
 234:     daddr_t start, end;
 235:     register struct disklabel *lp = (struct disklabel *)SEG5;
 236:     register struct partition *pp;
 237: 
 238:     if  ((openmask & partmask) == 0 && part != RAWPART)
 239:         {
 240:         mapseg5(label, LABELDESC);
 241:         pp = &lp->d_partitions[part];
 242:         start = pp->p_offset;
 243:         end = pp->p_offset + pp->p_size;
 244:         i = 0;
 245:         for (pp = lp->d_partitions; i < lp->d_npartitions; pp++,i++)
 246:             {
 247:             if  (pp->p_offset + pp->p_size <= start ||
 248:                  pp->p_offset >= end || i == RAWPART)
 249:                 continue;
 250:             if  (openmask & (1 << i))
 251:                 log(LOG_WARNING,
 252:                     "%s%d%c: overlaps open part (%c)\n",
 253:                     name, unit, part + 'a', i + 'a');
 254:             }
 255:         normalseg5();
 256:         }
 257:     return(0);
 258:     }
 259: 
 260: /*
 261:  * It was noticed that the ioctl processing of disklabels was the same
 262:  * for every disk driver.  Disk drivers should call this routine after
 263:  * handling ioctls (if any) particular to themselves.
 264: */
 265: 
 266: ioctldisklabel(dev, cmd, data, flag, disk, strat)
 267:     dev_t   dev;
 268:     int cmd;
 269:     register caddr_t    data;
 270:     int flag;
 271:     register struct dkdevice *disk;
 272:     int (*strat)();
 273:     {
 274:     struct  disklabel label;
 275:     register struct disklabel *lp = &label;
 276:     int error;
 277:     int flags;
 278: 
 279: /*
 280:  * Copy in mapped out label to the local copy on the stack.  We're in the
 281:  * high kernel at this point so saving the mapping is not necessary.
 282: */
 283:     mapseg5(disk->dk_label, LABELDESC);
 284:     bcopy((struct disklabel *)SEG5, lp, sizeof (*lp));
 285:     normalseg5();
 286: 
 287:     switch  (cmd)
 288:         {
 289:         case    DIOCGDINFO:
 290:             bcopy(lp, (struct disklabel *)data, sizeof (*lp));
 291:             return(0);
 292: /*
 293:  * Used internally by the kernel in init_main to verify that 'swapdev'
 294:  * is indeed a FS_SWAP partition.
 295:  *
 296:  * NOTE: the label address is the external click address!
 297: */
 298:         case    DIOCGPART:
 299:             ((struct partinfo *)data)->disklab =
 300:                     (struct disklabel *)disk->dk_label;
 301:             ((struct partinfo *)data)->part =
 302:                         &disk->dk_parts[dkpart(dev)];
 303:             return(0);
 304:         case    DIOCWLABEL:
 305:             if  ((flag & FWRITE) == 0)
 306:                 return(EBADF);
 307:             if  (*(int *)data)
 308:                 disk->dk_flags |= DKF_WLABEL;
 309:             else
 310:                 disk->dk_flags &= ~DKF_WLABEL;
 311:             return(0);
 312:         case    DIOCSDINFO:
 313:             if  ((flag & FWRITE) == 0)
 314:                 return(EBADF);
 315:             error = setdisklabel(lp, (struct disklabel *)data,
 316:                     disk->dk_flags & DKF_WLABEL ? 0
 317:                     : disk->dk_openmask);
 318: /*
 319:  * If no error was encountered setting the disklabel then we must copy
 320:  * out the new label from the local copy to the mapped out label.   Also
 321:  * update the partition tables (which are resident in the kernel).
 322: */
 323:             if  (error == 0)
 324:                 {
 325:                 mapseg5(disk->dk_label, LABELDESC);
 326:                 bcopy(lp,(struct disklabel *)SEG5,sizeof (*lp));
 327:                 normalseg5();
 328:                 bcopy(&lp->d_partitions, &disk->dk_parts,
 329:                     sizeof (lp->d_partitions));
 330:                 }
 331:             return(error);
 332:         case    DIOCWDINFO:
 333:             if  ((flag & FWRITE) == 0)
 334:                 return(EBADF);
 335:             error = setdisklabel(lp, (struct disklabel *)data,
 336:                     disk->dk_flags & DKF_WLABEL ? 0
 337:                     : disk->dk_openmask);
 338:             if  (error)
 339:                 return(error);
 340: /*
 341:  * Copy to external label.  Ah - need to also update the kernel resident
 342:  * partition tables!
 343: */
 344:             mapseg5(disk->dk_label, LABELDESC);
 345:             bcopy(lp,(struct disklabel *)SEG5,sizeof (*lp));
 346:             normalseg5();
 347:             bcopy(&lp->d_partitions, &disk->dk_parts,
 348:                 sizeof (lp->d_partitions));
 349: 
 350: /*
 351:  * We use the 'a' partition to write the label.  This probably shouldn't
 352:  * be wired in here but it's not worth creating another macro for.  Is it?
 353:  * The flags are faked to write enable the label area and that the drive is
 354:  * alive - it better be at this point or there is a problem in the open routine.
 355: */
 356:             flags = disk->dk_flags;
 357:             disk->dk_flags |= (DKF_ALIVE | DKF_WLABEL);
 358:             error = writedisklabel(dev & ~7, strat, lp);
 359:             disk->dk_flags = flags;
 360:             return(error);
 361:         }
 362:     return(EINVAL);
 363:     }
 364: 
 365: 
 366: /*
 367:  * This was extracted from the MSCP driver so it could be shared between
 368:  * all disk drivers which implement disk labels.
 369: */
 370: 
 371: partition_check(bp, dk)
 372:     struct  buf *bp;
 373:     struct  dkdevice *dk;
 374:     {
 375:     struct  partition *pi;
 376:     daddr_t sz;
 377: 
 378:     pi = &dk->dk_parts[dkpart(bp->b_dev)];
 379: 
 380:     /* Valid block in device partition */
 381:     sz = (bp->b_bcount + 511) >> 9;
 382:     if  (bp->b_blkno < 0 || bp->b_blkno + sz > pi->p_size)
 383:         {
 384:         sz = pi->p_size - bp->b_blkno;
 385:         /* if exactly at end of disk, return an EOF */
 386:         if  (sz == 0)
 387:             {
 388:             bp->b_resid = bp->b_bcount;
 389:             goto done;
 390:             }
 391:         /* or truncate if part of it fits */
 392:         if  (sz < 0)
 393:             {
 394:             bp->b_error = EINVAL;
 395:             goto bad;
 396:             }
 397:         bp->b_bcount = dbtob(sz);   /* compute byte count */
 398:         }
 399: /*
 400:  * Check for write to write-protected label area.  This does not include
 401:  * sector 0 which is the boot block.
 402: */
 403:     if  (bp->b_blkno + pi->p_offset <= LABELSECTOR &&
 404:          bp->b_blkno + pi->p_offset + sz > LABELSECTOR &&
 405:          !(bp->b_flags & B_READ) && !(dk->dk_flags & DKF_WLABEL))
 406:         {
 407:         bp->b_error = EROFS;
 408:         goto bad;
 409:         }
 410:     return(1);      /* success */
 411: bad:
 412:     return(-1);
 413: done:
 414:     return(0);
 415:     }

Defined functions

dkcksum defined in line 200; used 4 times
setdisklabel defined in line 113; used 3 times
writedisklabel defined in line 153; used 2 times

Defined macros

RAWPART defined in line 222; used 2 times
Last modified: 1998-04-04
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3879
Valid CSS Valid XHTML 1.0 Strict