/* * 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. * * Returns null on success and an error string on failure. */ const char * readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *osdep) { int spoofonly = 0; struct buf *bp = NULL; const char *msg = "no disk label"; int i; struct disklabel fallbacklabel; /* minimal requirements for archetypal disk label */ if (lp->d_secsize == 0) lp->d_secsize = DEV_BSIZE; if (lp->d_secperunit == 0) lp->d_secperunit = 0x1fffffff; if (lp->d_secpercyl == 0) return "invalid geometry"; lp->d_npartitions = RAW_PART + 1; for (i = 0; i < RAW_PART; i++) { lp->d_partitions[i].p_size = 0; lp->d_partitions[i].p_offset = 0; } if (lp->d_partitions[i].p_size == 0) lp->d_partitions[i].p_size = 0x1fffffff; lp->d_partitions[i].p_offset = 0; fallbacklabel = *lp; /* get a buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; msg = readliflabel(bp, strat, lp, osdep, 0, 0, spoofonly); #if defined(CD9660) if (msg && iso_disklabelspoof(dev, strat, lp) == 0) msg = NULL; #endif /* If there was an error, still provide a decent fake one. */ if (msg) *lp = fallbacklabel; if (bp) { brelse(bp, BC_INVAL); } return (msg); }
/* * Write disk label back to device after modification. */ int writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *osdep) { const char *msg = "no disk label"; struct buf *bp; struct disklabel dl; struct cpu_disklabel cdl; int labeloffset, error, partoff = 0, cyl = 0; /* get a buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; /* * I once played with the thought of using osdep->label{tag,sector} * as a cache for knowing where (and what) to write. However, now I * think it might be useful to reprobe if someone has written * a newer disklabel of another type with disklabel(8) and -r. */ dl = *lp; msg = readliflabel(bp, strat, &dl, &cdl, &partoff, &cyl, 0); labeloffset = LABELOFFSET; if (msg) { if (partoff == -1) return EIO; /* Write it in the regular place with native byte order. */ labeloffset = LABELOFFSET; bp->b_blkno = partoff + LABELSECTOR; bp->b_cylinder = cyl; bp->b_bcount = lp->d_secsize; } *(struct disklabel *)((char *)bp->b_data + labeloffset) = *lp; bp->b_cflags = BC_BUSY; bp->b_flags = B_WRITE; (*strat)(bp); error = biowait(bp); brelse(bp, BC_INVAL); return (error); }
/* * Write disk label back to device after modification. */ int writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp) { int error = EIO, partoff = -1; 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 (readliflabel(bp, strat, lp, &partoff, 1) == 0) { bp->b_blkno = partoff + LABELSECTOR; offset = LABELOFFSET; } else if (readdoslabel(bp, strat, lp, &partoff, 1) == 0) { bp->b_blkno = DL_BLKTOSEC(lp, partoff + DOS_LABELSECTOR) * DL_BLKSPERSEC(lp); offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR); } else goto done; /* Read it in, slap the new label in, and write it back out */ bp->b_bcount = lp->d_secsize; CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); SET(bp->b_flags, B_BUSY | B_READ | B_RAW); (*strat)(bp); if ((error = biowait(bp)) != 0) goto done; 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); }
/* * 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. */ 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 = readliflabel(bp, strat, lp, NULL, spoofonly); if (error == 0) goto done; 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); }