int readliflabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp, int *partoffp, int spoofonly) { struct buf *dbp = NULL; struct lifdir *p; struct lifvol *lvp; int error = 0; int fsoff = 0, openbsdstart = MAXLIFSPACE, i; /* read LIF volume header */ bp->b_blkno = btodb(LIF_VOLSTART); 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 (biowait(bp)) return (bp->b_error); lvp = (struct lifvol *)bp->b_data; if (lvp->vol_id != LIF_VOL_ID) { error = EINVAL; /* no LIF volume header */ goto done; } dbp = geteblk(LIF_DIRSIZE); dbp->b_dev = bp->b_dev; /* read LIF directory */ dbp->b_blkno = lifstodb(lvp->vol_addr); dbp->b_bcount = lp->d_secsize; CLR(dbp->b_flags, B_READ | B_WRITE | B_DONE); SET(dbp->b_flags, B_BUSY | B_READ | B_RAW); (*strat)(dbp); if (biowait(dbp)) { error = dbp->b_error; goto done; } /* scan for LIF_DIR_FS dir entry */ for (i=0, p=(struct lifdir *)dbp->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; } /* Only came here to find the offset... */ if (partoffp) goto finished; if (p->dir_type == LIF_DIR_HPLBL) { struct hpux_label *hl; struct partition *pp; u_int8_t fstype; int i; /* read LIF directory */ dbp->b_blkno = lifstodb(p->dir_addr); dbp->b_bcount = lp->d_secsize; CLR(dbp->b_flags, B_READ | B_WRITE | B_DONE); SET(dbp->b_flags, B_BUSY | B_READ | B_RAW); (*strat)(dbp); if (biowait(dbp)) { error = dbp->b_error; goto done; } hl = (struct hpux_label *)dbp->b_data; if (hl->hl_magic1 != hl->hl_magic2 || hl->hl_magic != HPUX_MAGIC || hl->hl_version != 1) { error = EINVAL; /* HPUX label magic mismatch */ goto done; } lp->d_bbsize = 8192; lp->d_sbsize = 8192; 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); /* drop through */ } finished: /* record the OpenBSD partition's placement for the caller */ if (partoffp) *partoffp = fsoff; else { DL_SETBSTART(lp, openbsdstart); DL_SETBEND(lp, DL_GETDSIZE(lp)); /* XXX */ } /* don't read the on-disk label if we are in spoofed-only mode */ if (spoofonly) goto done; bp->b_blkno = fsoff + LABELSECTOR; 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 (biowait(bp)) { error = bp->b_error; goto done; } /* * Do OpenBSD disklabel validation/adjustment. * * N.B: No matter what the bits are on the disk, we now have the * OpenBSD disklabel for this lif disk. DO NOT proceed to * readdoslabel(), iso_spooflabel(), etc. */ checkdisklabel(bp->b_data, lp, openbsdstart, DL_GETDSIZE(lp)); error = 0; done: if (dbp) { dbp->b_flags |= B_INVAL; brelse(dbp); } return (error); }
int lif_open(const char *path, struct open_file *f) { struct file *fp; struct lifdir *dp; const char *p, *q; struct lif_load load; int err, l; size_t buf_size; #ifdef LIFDEBUG if (debug) printf("lif_open(%s, %p)\n", path, f); #endif fp = alloc(sizeof(*fp)); /* XXX we're assuming here that sizeof(fp->f_buf) >= LIF_FILESTART */ err = (*f->f_dev->dv_strategy)(f->f_devdata, F_READ, 0, sizeof(fp->f_buf), &fp->f_buf, &buf_size); if (err || buf_size != sizeof(fp->f_buf)) { #ifdef LIFDEBUG if (debug) printf("lif_open: unable to read LIF header (%d)\n", err); #endif } else if ((fp->f_lp = (struct lifvol *)fp->f_buf)->vol_id == LIF_VOL_ID) { f->f_fsdata = fp; fp->f_ld = (struct lifdir *)(fp->f_buf + LIF_DIRSTART); fp->f_seek = 0; fp->f_rd = fp->f_ld; fp->f_nfiles = lifstob(fp->f_lp->vol_dirsize) / sizeof(struct lifdir); /* no dirs on the lif */ for (p = path + (l = strlen(path)); p >= path; p--) if (*p == '/') { p++; break; } if (p > path) path = p; } else err = EINVAL; if (!err && *path != '.') { fp->f_isdir = 0; err = ENOENT; for (dp = fp->f_ld; dp < &fp->f_ld[fp->f_nfiles]; dp++) { #ifdef LIFDEBUG if (debug) printf("lif_open: " "%s <--> '%c%c%c%c%c%c%c%c%c%c'\n", path, dp->dir_name[0], dp->dir_name[1], dp->dir_name[2], dp->dir_name[3], dp->dir_name[4], dp->dir_name[5], dp->dir_name[6], dp->dir_name[7], dp->dir_name[8], dp->dir_name[9]); #endif for (p = path, q = dp->dir_name; *q && *q != ' '; q++, p++) if (tolower(*q) != tolower(*p)) break; if ((!*q || *q == ' ') && !*p) { err = 0; break; } } if (!err) { fp->f_off = lifstodb(dp->dir_addr); if (!(err =(f->f_dev->dv_strategy)(f->f_devdata, F_READ, fp->f_off, sizeof(load), &load, &buf_size)) && buf_size == sizeof(load)) { /* no checksum */ fp->f_count = load.count - sizeof(int); fp->f_off = dbtob(fp->f_off) + sizeof(load); #ifdef LIFDEBUG if (debug) printf("lif_open: %u @ %u [%x]\n", fp->f_count, fp->f_off, load.address); #endif } else if (!err) err = EIO; } } else fp->f_isdir = 1; if (err) { free (fp, sizeof(*fp)); f->f_fsdata = NULL; } #ifdef LIFDEBUG if (debug) printf("ret(%d)\n", err); #endif return err; }