/* * 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 (readdpmelabel(bp, strat, lp, &partoff, 1) == 0) { bp->b_blkno = partoff; offset = 0; } 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); }
int readsgilabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp, daddr_t *partoffp, int spoofonly) { struct sgilabel *dlp; int i, *p, cs = 0; daddr_t fsoffs, fsend; int error, offset; /* if successful, locate disk label within block and validate */ error = readdisksector(bp, strat, lp, 0); if (error) return (error); fsoffs = DL_SECTOBLK(lp, DL_GETBSTART(lp)); fsend = DL_SECTOBLK(lp, DL_GETBEND(lp)); dlp = (struct sgilabel *)(bp->b_data + LABELOFFSET); if (dlp->magic != htobe32(SGILABEL_MAGIC)) goto finished; if (dlp->partitions[0].blocks == 0) return (EINVAL); fsoffs = (long long)dlp->partitions[0].first; fsend = fsoffs + dlp->partitions[0].blocks; /* Only came here to find the offset... */ if (partoffp) { *partoffp = fsoffs; goto finished; } p = (int *)dlp; i = sizeof(struct sgilabel) / sizeof(int); while (i--) cs += *p++; if (cs != 0) return (EINVAL); /* sgilabel checksum error */ /* Spoof info from sgi label, in case there is no OpenBSD label. */ lp->d_npartitions = MAXPARTITIONS; for (i = 0; i < 16; i++) { int bsd = maptab[i].m; int type = maptab[i].b; if (spoofonly && type != FS_UNUSED && type != FS_OTHER) continue; DL_SETPOFFSET(&lp->d_partitions[bsd], dlp->partitions[i].first); DL_SETPSIZE(&lp->d_partitions[bsd], dlp->partitions[i].blocks); lp->d_partitions[bsd].p_fstype = type; if (type == FS_BSDFFS) { lp->d_partitions[bsd].p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(1024, 8); lp->d_partitions[bsd].p_cpg = 16; } } DL_SETBSTART(lp, DL_BLKTOSEC(lp, fsoffs)); DL_SETBEND(lp, DL_BLKTOSEC(lp, fsend)); lp->d_version = 1; lp->d_flags = D_VENDOR; lp->d_checksum = 0; lp->d_checksum = dkcksum(lp); finished: /* record the OpenBSD partition's placement for the caller */ if (partoffp) *partoffp = fsoffs; else { DL_SETBSTART(lp, DL_BLKTOSEC(lp, fsoffs)); DL_SETBEND(lp, DL_BLKTOSEC(lp, fsend)); } /* don't read the on-disk label if we are in spoofed-only mode */ if (spoofonly) return (0); error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, fsoffs + LABELSECTOR)); if (error) return (error); offset = DL_BLKOFFSET(lp, fsoffs + LABELSECTOR) + LABELOFFSET; /* * Do OpenBSD disklabel validation/adjustment. * * N.B: No matter what the bits are on the disk, we now have the * OpenBSD disklabel for this sgi disk. DO NOT proceed to * readdoslabel(), iso_spooflabel(), etc. */ checkdisklabel(bp->b_data + offset, lp, fsoffs, fsend); return (0); }