text: /*	$OpenBSD: disksubr.c,v 1.20 2015/09/27 20:20:23 krw Exp $	*/
  /*	$NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $	*/
  
  /*
   * Copyright (c) 1996 Theo de Raadt
   * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   * 3. Neither the name of the University nor the names of its contributors
   *    may be used to endorse or promote products derived from this software
   *    without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   */
  
  #include <sys/param.h>
  #include <sys/systm.h>
  #include <sys/buf.h>
  #include <sys/disklabel.h>
  #include <sys/disk.h>
  
  /*
   * Attempt to read a disk label from a device
   * using the indicated strategy routine.
   * The label must be partly set up before this:
   * secpercyl, secsize and anything required for a block i/o read
   * operation in the driver's strategy/start routines
   * must be filled in before calling us.
   *
   * If dos partition table requested, attempt to load it and
   * find disklabel inside a DOS partition.
   *
   * We would like to check if each MBR has a valid DOSMBR_SIGNATURE, but
   * we cannot because it doesn't always exist. So.. we assume the
   * MBR is valid.
   */
  int
  readdisklabel(dev_t dev, void (*strat)(struct buf *),
      struct disklabel *lp, int spoofonly)
  {
  	struct buf *bp = NULL;
  	int error;
  
  	if ((error = initdisklabel(lp)))
  		goto done;
  
  	/* get a buffer and initialize it */
  	bp = geteblk((int)lp->d_secsize);
  	bp->b_dev = dev;
  
  	error = readdoslabel(bp, strat, lp, NULL, spoofonly);
  	if (error == 0)
  		goto done;
  
  #if defined(CD9660)
  	error = iso_disklabelspoof(dev, strat, lp);
  	if (error == 0)
  		goto done;
  #endif
  #if defined(UDF)
  	error = udf_disklabelspoof(dev, strat, lp);
  	if (error == 0)
  		goto done;
  #endif
  
  done:
  	if (bp) {
  		bp->b_flags |= B_INVAL;
  		brelse(bp);
  	}
  	disk_change = 1;
  	return (error);
  }
  
  /*
   * Write disk label back to device after modification.
   */
  int
  writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp)
  {
  	daddr_t partoff = -1;
  	int error = EIO;
  	int offset;
  	struct disklabel *dlp;
  	struct buf *bp = NULL;
  
  	/* get a buffer and initialize it */
  	bp = geteblk((int)lp->d_secsize);
  	bp->b_dev = dev;
  
  	if (readdoslabel(bp, strat, lp, &partoff, 1) != 0)
  		goto done;
  
  	/* Read it in, slap the new label in, and write it back out */
  	error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, partoff +
  	    DOS_LABELSECTOR));
  	if (error)
  		goto done;
  	offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR);
  
  	dlp = (struct disklabel *)(bp->b_data + offset);
  	*dlp = *lp;
  	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
  	SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW);
  	(*strat)(bp);
  	error = biowait(bp);
  
  done:
  	if (bp) {
  		bp->b_flags |= B_INVAL;
  		brelse(bp);
  	}
  	disk_change = 1;
  	return (error);
  }
  