#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
#include <sys/disk.h>
int readliflabel(struct buf *, void (*)(struct buf *),
struct disklabel *, daddr_t *, int);
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;
bp = geteblk(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);
}
int
readliflabel(struct buf *bp, void (*strat)(struct buf *),
struct disklabel *lp, daddr_t *partoffp, int spoofonly)
{
struct lifdir *p;
struct lifvol *lvp;
int error = 0;
daddr_t fsoff = 0, openbsdstart = MAXLIFSPACE;
int i;
error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
btodb(LIF_VOLSTART)));
if (error)
return (error);
lvp = (struct lifvol *)bp->b_data;
if (lvp->vol_id != LIF_VOL_ID) {
error = EINVAL;
goto done;
}
error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
lifstodb(lvp->vol_addr)));
if (error)
goto done;
for (i=0, p=(struct lifdir *)bp->b_data; i < LIF_NUMDIR; p++, i++) {
if (p->dir_type == LIF_DIR_FS || p->dir_type == LIF_DIR_HPLBL)
break;
}
if (p->dir_type == LIF_DIR_FS) {
fsoff = lifstodb(p->dir_addr);
openbsdstart = 0;
goto finished;
}
if (partoffp)
goto finished;
if (p->dir_type == LIF_DIR_HPLBL) {
struct hpux_label *hl;
struct partition *pp;
u_int8_t fstype;
int i;
error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
lifstodb(p->dir_addr)));
if (error)
goto done;
hl = (struct hpux_label *)bp->b_data;
if (hl->hl_magic1 != hl->hl_magic2 ||
hl->hl_magic != HPUX_MAGIC || hl->hl_version != 1) {
error = EINVAL;
goto done;
}
for (i = 0; i < MAXPARTITIONS; i++) {
DL_SETPSIZE(&lp->d_partitions[i], 0);
DL_SETPOFFSET(&lp->d_partitions[i], 0);
lp->d_partitions[i].p_fstype = 0;
}
for (i = 0; i < HPUX_MAXPART; i++) {
if (!hl->hl_flags[i])
continue;
if (hl->hl_flags[i] == HPUX_PART_ROOT) {
pp = &lp->d_partitions[0];
fstype = FS_BSDFFS;
} else if (hl->hl_flags[i] == HPUX_PART_SWAP) {
pp = &lp->d_partitions[1];
fstype = FS_SWAP;
} else if (hl->hl_flags[i] == HPUX_PART_BOOT) {
pp = &lp->d_partitions[RAW_PART + 1];
fstype = FS_BSDFFS;
} else
continue;
DL_SETPSIZE(pp, hl->hl_parts[i].hlp_length * 2);
DL_SETPOFFSET(pp, hl->hl_parts[i].hlp_start * 2);
pp->p_fstype = fstype;
}
DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
DL_SETPOFFSET(&lp->d_partitions[RAW_PART], 0);
lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
lp->d_npartitions = MAXPARTITIONS;
lp->d_magic = DISKMAGIC;
lp->d_magic2 = DISKMAGIC;
lp->d_version = 1;
lp->d_checksum = 0;
lp->d_checksum = dkcksum(lp);
}
finished:
if (partoffp)
*partoffp = fsoff;
else {
DL_SETBSTART(lp, DL_BLKTOSEC(lp, openbsdstart));
DL_SETBEND(lp, DL_GETDSIZE(lp));
}
if (spoofonly)
goto done;
error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, fsoff +
LABELSECTOR));
if (error)
goto done;
error = checkdisklabel(bp->b_dev, bp->b_data, lp, openbsdstart,
DL_GETDSIZE(lp));
done:
return (error);
}
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;
bp = geteblk(lp->d_secsize);
bp->b_dev = dev;
if (readliflabel(bp, strat, lp, &partoff, 1) == 0) {
error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
partoff + LABELSECTOR));
offset = LABELOFFSET;
} else if (readdoslabel(bp, strat, lp, &partoff, 1) == 0) {
error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
partoff + DOS_LABELSECTOR));
offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR);
} else
goto done;
if (error)
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);
}