void __wdstart(struct wd_softc *wd, struct buf *bp) { struct disklabel *lp; u_int64_t nsecs; lp = wd->sc_dk.dk_label; wd->sc_wdc_bio.blkno = DL_BLKTOSEC(lp, bp->b_blkno + DL_SECTOBLK(lp, DL_GETPOFFSET(&lp->d_partitions[DISKPART(bp->b_dev)]))); wd->sc_wdc_bio.blkdone =0; wd->sc_bp = bp; /* * If we're retrying, retry in single-sector mode. This will give us * the sector number of the problem, and will eventually allow the * transfer to succeed. */ if (wd->retries >= WDIORETRIES_SINGLE) wd->sc_wdc_bio.flags = ATA_SINGLE; else wd->sc_wdc_bio.flags = 0; nsecs = howmany(bp->b_bcount, lp->d_secsize); if ((wd->sc_flags & WDF_LBA48) && /* use LBA48 only if really need */ ((wd->sc_wdc_bio.blkno + nsecs - 1 >= LBA48_THRESHOLD) || (nsecs > 0xff))) wd->sc_wdc_bio.flags |= ATA_LBA48; if (wd->sc_flags & WDF_LBA) wd->sc_wdc_bio.flags |= ATA_LBA; if (bp->b_flags & B_READ) wd->sc_wdc_bio.flags |= ATA_READ; wd->sc_wdc_bio.bcount = bp->b_bcount; wd->sc_wdc_bio.databuf = bp->b_data; wd->sc_wdc_bio.wd = wd; /* Instrumentation. */ disk_busy(&wd->sc_dk); switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) { case WDC_TRY_AGAIN: timeout_add_sec(&wd->sc_restart_timeout, 1); break; case WDC_QUEUED: break; case WDC_COMPLETE: /* * This code is never executed because we never set * the ATA_POLL flag above */ #if 0 if (wd->sc_wdc_bio.flags & ATA_POLL) wddone(wd); #endif break; default: panic("__wdstart: bad return code from wdc_ata_bio()"); } }
/* * Display a particular partition. */ void display_partition(FILE *f, struct disklabel *lp, int i, char unit) { volatile struct partition *pp = &lp->d_partitions[i]; double p_size; p_size = scale(DL_GETPSIZE(pp), unit, lp); if (DL_GETPSIZE(pp)) { u_int32_t frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); u_int32_t fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); if (p_size < 0) fprintf(f, " %c: %16llu %16llu ", 'a' + i, DL_GETPSIZE(pp), DL_GETPOFFSET(pp)); else fprintf(f, " %c: %15.*f%c %16llu ", 'a' + i, unit == 'B' ? 0 : 1, p_size, unit, DL_GETPOFFSET(pp)); if (pp->p_fstype < FSMAXTYPES) fprintf(f, "%7.7s", fstypenames[pp->p_fstype]); else fprintf(f, "%7d", pp->p_fstype); switch (pp->p_fstype) { case FS_BSDFFS: fprintf(f, " %5u %5u %4hu ", fsize, fsize * frag, pp->p_cpg); break; default: fprintf(f, "%19.19s", ""); break; } if (mountpoints[i] != NULL) fprintf(f, "# %s", mountpoints[i]); putc('\n', f); } }
void rdstrategy(struct buf *bp) { struct rd_softc *sc; struct partition *p; size_t off, xfer; caddr_t addr; int s; sc = rdlookup(DISKUNIT(bp->b_dev)); if (sc == NULL) { bp->b_error = ENXIO; goto bad; } /* Validate the request. */ if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1) goto done; /* Do the transfer. */ /* XXX: Worry about overflow when computing off? */ p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; off = DL_GETPOFFSET(p) * sc->sc_dk.dk_label->d_secsize + (u_int64_t)bp->b_blkno * DEV_BSIZE; if (off > rd_root_size) off = rd_root_size; xfer = bp->b_bcount; if (xfer > rd_root_size - off) xfer = rd_root_size - off; addr = rd_root_image + off; if (bp->b_flags & B_READ) memcpy(bp->b_data, addr, xfer); else memcpy(addr, bp->b_data, xfer); bp->b_resid = bp->b_bcount - xfer; goto done; bad: bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; done: s = splbio(); biodone(bp); splx(s); if (sc != NULL) device_unref(&sc->sc_dev); }
/* * If we are installing a boot program that doesn't fit in d_bbsize * we need to mark those partitions that the boot overflows into. * This allows newfs to prevent creation of a filesystem where it might * clobber bootstrap code. */ void setbootflag(struct disklabel *lp) { struct partition *pp; int i, errors = 0; u_int64_t bend; char part; if (bootbuf == NULL) return; bend = (u_int64_t)bootsize / lp->d_secsize; for (i = 0; i < lp->d_npartitions; i++) { if (i == RAW_PART) /* It will *ALWAYS* overlap 'c'. */ continue; pp = &lp->d_partitions[i]; if (DL_GETPSIZE(pp) == 0) /* Partition is unused. */ continue; if (bend <= DL_GETPOFFSET(pp)) { /* Boot blocks end before this partition starts. */ if (pp->p_fstype == FS_BOOT) pp->p_fstype = FS_UNUSED; continue; } part = 'a' + i; switch (pp->p_fstype) { case FS_BOOT: /* Already marked. */ break; case FS_UNUSED: /* Mark. */ pp->p_fstype = FS_BOOT; warnx("warning, boot overlaps partition %c, %s", part, "marked as FS_BOOT"); break; default: warnx("boot overlaps used partition %c", part); errors++; break; } } if (errors) errx(4, "cannot install boot program"); }
/* * Check disklabel for errors and fill in * derived fields according to supplied values. */ int checklabel(struct disklabel *lp) { struct partition *pp; int i, errors = 0; char part; if (lp->d_secsize == 0) { warnx("sector size %d", lp->d_secsize); return (1); } if (lp->d_nsectors == 0) { warnx("sectors/track %d", lp->d_nsectors); return (1); } if (lp->d_ntracks == 0) { warnx("tracks/cylinder %d", lp->d_ntracks); return (1); } if (lp->d_ncylinders == 0) { warnx("cylinders/unit %d", lp->d_ncylinders); errors++; } if (lp->d_secpercyl == 0) lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; if (DL_GETDSIZE(lp) == 0) DL_SETDSIZE(lp, (u_int64_t)lp->d_secpercyl * lp->d_ncylinders); if (lp->d_bbsize == 0) { warnx("boot block size %d", lp->d_bbsize); errors++; } else if (lp->d_bbsize % lp->d_secsize) warnx("warning, boot block size %% sector-size != 0"); if (lp->d_sbsize == 0) { warnx("super block size %d", lp->d_sbsize); errors++; } else if (lp->d_sbsize % lp->d_secsize) warnx("warning, super block size %% sector-size != 0"); if (lp->d_npartitions > MAXPARTITIONS) warnx("warning, number of partitions (%d) > MAXPARTITIONS (%d)", lp->d_npartitions, MAXPARTITIONS); for (i = 0; i < lp->d_npartitions; i++) { part = 'a' + i; pp = &lp->d_partitions[i]; if (DL_GETPSIZE(pp) == 0 && DL_GETPOFFSET(pp) != 0) warnx("warning, partition %c: size 0, but offset %llu", part, DL_GETPOFFSET(pp)); #ifdef SUN_CYLCHECK if (lp->d_flags & D_VENDOR) { if (i != RAW_PART && DL_GETPSIZE(pp) % lp->d_secpercyl) warnx("warning, partition %c: size %% " "cylinder-size != 0", part); if (i != RAW_PART && DL_GETPOFFSET(pp) % lp->d_secpercyl) warnx("warning, partition %c: offset %% " "cylinder-size != 0", part); } #endif #ifdef SUN_AAT0 if ((lp->d_flags & D_VENDOR) && i == 0 && DL_GETPSIZE(pp) != 0 && DL_GETPOFFSET(pp) != 0) { warnx("this architecture requires partition 'a' to " "start at sector 0"); errors++; } #endif if (DL_GETPOFFSET(pp) > DL_GETDSIZE(lp)) { warnx("partition %c: offset past end of unit", part); errors++; } if (DL_GETPOFFSET(pp) + DL_GETPSIZE(pp) > DL_GETDSIZE(lp)) { warnx("partition %c: partition extends past end of unit", part); errors++; } #if 0 if (pp->p_frag == 0 && pp->p_fsize != 0) { warnx("partition %c: block size < fragment size", part); errors++; } #endif } for (; i < MAXPARTITIONS; i++) { part = 'a' + i; pp = &lp->d_partitions[i]; if (DL_GETPSIZE(pp) || DL_GETPOFFSET(pp)) warnx("warning, unused partition %c: size %llu " "offset %llu", part, DL_GETPSIZE(pp), DL_GETPOFFSET(pp)); } return (errors > 0); }
/* * Given a BSD disk label, update the Sun disklabel * pointed to by cp with the new info. Note that the * Sun disklabel may have other info we need to keep. */ static int disklabel_bsd_to_sun(struct disklabel *lp, struct sun_disklabel *sl) { struct partition *npp; struct sun_dkpart *spp; int i, secpercyl; u_short cksum, *sp1, *sp2; /* Enforce preconditions */ if (lp->d_secsize != DEV_BSIZE || lp->d_nsectors == 0 || lp->d_ntracks == 0) return (EINVAL); /* Format conversion. */ bzero(sl, sizeof(*sl)); memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname)); sl->sl_pcylinders = lp->d_ncylinders + lp->d_acylinders; /* XXX */ sl->sl_ncylinders = lp->d_ncylinders; sl->sl_acylinders = lp->d_acylinders; sl->sl_ntracks = lp->d_ntracks; sl->sl_nsectors = lp->d_nsectors; memcpy(&sl->sl_uid, &lp->d_uid, sizeof(lp->d_uid)); secpercyl = sl->sl_nsectors * sl->sl_ntracks; for (i = 0; i < 8; i++) { spp = &sl->sl_part[i]; npp = &lp->d_partitions[i]; spp->sdkp_cyloffset = 0; spp->sdkp_nsectors = 0; if (DL_GETPSIZE(npp)) { if (DL_GETPOFFSET(npp) % secpercyl) return (EINVAL); spp->sdkp_cyloffset = DL_GETPOFFSET(npp) / secpercyl; spp->sdkp_nsectors = DL_GETPSIZE(npp); } } sl->sl_magic = SUN_DKMAGIC; for (i = 0; i < SUNXPART; i++) { spp = &sl->sl_xpart[i]; npp = &lp->d_partitions[i+8]; spp->sdkp_cyloffset = 0; spp->sdkp_nsectors = 0; if (DL_GETPSIZE(npp)) { if (DL_GETPOFFSET(npp) % secpercyl) return (EINVAL); spp->sdkp_cyloffset = DL_GETPOFFSET(npp) / secpercyl; spp->sdkp_nsectors = DL_GETPSIZE(npp); } } for (i = 0; i < MAXPARTITIONS; i++) { npp = &lp->d_partitions[i]; sl->sl_types[i] = npp->p_fstype; sl->sl_fragblock[i] = npp->p_fragblock; sl->sl_cpg[i] = npp->p_cpg; } sl->sl_xpmag = SL_XPMAGTYP; sl->sl_xpsum = sun_extended_sum(sl, &sl->sl_xxx1); /* Correct the XOR check. */ sp1 = (u_short *)sl; sp2 = (u_short *)(sl + 1); sl->sl_cksum = cksum = 0; while (sp1 < sp2) cksum ^= *sp1++; sl->sl_cksum = cksum; return (0); }
/* * cdstart looks to see if there is a buf waiting for the device * and that the device is not already busy. If both are true, * It deques the buf and creates a scsi command to perform the * transfer in the buf. The transfer request will call scsi_done * on completion, which will in turn call this routine again * so that the next queued transfer is performed. * The bufs are queued by the strategy routine (cdstrategy) * * This routine is also called after other non-queued requests * have been made of the scsi driver, to ensure that the queue * continues to be drained. * * must be called at the correct (highish) spl level * cdstart() is called at splbio from cdstrategy, cdrestart and scsi_done */ void cdstart(void *v) { struct cd_softc *cd = v; struct scsi_link *sc_link = cd->sc_link; struct buf *bp = 0; struct buf *dp; struct scsi_rw_big cmd_big; struct scsi_rw cmd_small; struct scsi_generic *cmdp; int blkno, nblks, cmdlen, error; struct partition *p; splassert(IPL_BIO); SC_DEBUG(sc_link, SDEV_DB2, ("cdstart\n")); /* * Check if the device has room for another command */ while (sc_link->openings > 0) { /* * there is excess capacity, but a special waits * It'll need the adapter as soon as we clear out of the * way and let it run (user level wait). */ if (sc_link->flags & SDEV_WAITING) { sc_link->flags &= ~SDEV_WAITING; wakeup((caddr_t)sc_link); return; } /* * See if there is a buf with work for us to do.. */ dp = &cd->buf_queue; if ((bp = dp->b_actf) == NULL) /* yes, an assign */ return; dp->b_actf = bp->b_actf; /* * If the device has become invalid, abort all the * reads and writes until all files have been closed and * re-opened */ if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) { bp->b_error = EIO; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; biodone(bp); continue; } /* * We have a buf, now we should make a command * * First, translate the block to absolute and put it in terms * of the logical blocksize of the device. */ blkno = bp->b_blkno / (cd->sc_dk.dk_label->d_secsize / DEV_BSIZE); p = &cd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; blkno += DL_GETPOFFSET(p); nblks = howmany(bp->b_bcount, cd->sc_dk.dk_label->d_secsize); /* * Fill out the scsi command. If the transfer will * fit in a "small" cdb, use it. */ if (!(sc_link->flags & SDEV_ATAPI) && !(sc_link->quirks & SDEV_ONLYBIG) && ((blkno & 0x1fffff) == blkno) && ((nblks & 0xff) == nblks)) { /* * We can fit in a small cdb. */ bzero(&cmd_small, sizeof(cmd_small)); cmd_small.opcode = (bp->b_flags & B_READ) ? READ_COMMAND : WRITE_COMMAND; _lto3b(blkno, cmd_small.addr); cmd_small.length = nblks & 0xff; cmdlen = sizeof(cmd_small); cmdp = (struct scsi_generic *)&cmd_small; } else { /* * Need a large cdb. */ bzero(&cmd_big, sizeof(cmd_big)); cmd_big.opcode = (bp->b_flags & B_READ) ? READ_BIG : WRITE_BIG; _lto4b(blkno, cmd_big.addr); _lto2b(nblks, cmd_big.length); cmdlen = sizeof(cmd_big); cmdp = (struct scsi_generic *)&cmd_big; } /* Instrumentation. */ disk_busy(&cd->sc_dk); /* * Call the routine that chats with the adapter. * Note: we cannot sleep as we may be an interrupt */ error = scsi_scsi_cmd(sc_link, cmdp, cmdlen, (u_char *) bp->b_data, bp->b_bcount, SCSI_RETRIES, 30000, bp, SCSI_NOSLEEP | ((bp->b_flags & B_READ) ? SCSI_DATA_IN : SCSI_DATA_OUT)); switch (error) { case 0: timeout_del(&cd->sc_timeout); break; case EAGAIN: /* * The device can't start another i/o. Try again later. */ dp->b_actf = bp; disk_unbusy(&cd->sc_dk, 0, 0); timeout_add(&cd->sc_timeout, 1); return; default: disk_unbusy(&cd->sc_dk, 0, 0); printf("%s: not queued, error %d\n", cd->sc_dev.dv_xname, error); break; } } }
/* * Given a UniOS/ISI disk label, set lp to a BSD disk label. * * The BSD label is cleared out before this is called. */ int disklabel_om_to_bsd(struct sun_disklabel *sl, struct disklabel *lp) { struct partition *npp; struct sun_dkpart *spp; int i, secpercyl; u_short cksum = 0, *sp1, *sp2; /* Verify the XOR check. */ sp1 = (u_short *)sl; sp2 = (u_short *)(sl + 1); while (sp1 < sp2) cksum ^= *sp1++; if (cksum != 0) return (EINVAL); /* UniOS disk label, bad checksum */ /* Format conversion. */ lp->d_magic = DISKMAGIC; lp->d_magic2 = DISKMAGIC; lp->d_flags = D_VENDOR; memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname)); lp->d_secsize = DEV_BSIZE; lp->d_nsectors = sl->sl_nsectors; lp->d_ntracks = sl->sl_ntracks; lp->d_ncylinders = sl->sl_ncylinders; secpercyl = sl->sl_nsectors * sl->sl_ntracks; lp->d_secpercyl = secpercyl; /* If unset or initialized as full disk, permit refinement */ if (DL_GETDSIZE(lp) == 0 || DL_GETDSIZE(lp) == MAXDISKSIZE) DL_SETDSIZE(lp, (u_int64_t)secpercyl * sl->sl_ncylinders); lp->d_version = 1; memcpy(&lp->d_uid, &sl->sl_uid, sizeof(sl->sl_uid)); lp->d_acylinders = sl->sl_acylinders; lp->d_npartitions = MAXPARTITIONS; /* These are as defined in <ufs/ffs/fs.h> */ lp->d_bbsize = 8192; /* XXX */ lp->d_sbsize = 8192; /* XXX */ for (i = 0; i < 8; i++) { spp = &sl->sl_part[i]; npp = &lp->d_partitions[i]; /* UniOS label uses blkoffset, not cyloffset */ DL_SETPOFFSET(npp, spp->sdkp_cyloffset); DL_SETPSIZE(npp, spp->sdkp_nsectors); if (DL_GETPSIZE(npp) == 0) { npp->p_fstype = FS_UNUSED; } else { npp->p_fstype = sun_fstypes[i]; if (npp->p_fstype == FS_BSDFFS) { /* * The sun label does not store the FFS fields, * so just set them with default values here. */ npp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(2048, 8); npp->p_cpg = 16; } } } /* * XXX BandAid XXX * UniOS rootfs sits on part c which don't begin at sect 0, * and impossible to mount. Thus, make it usable as part b. * XXX how to setup a swap partition on disks shared with UniOS??? */ if (sl->sl_rpm == 0 && DL_GETPOFFSET(&lp->d_partitions[2]) != 0) { lp->d_partitions[1] = lp->d_partitions[2]; lp->d_partitions[1].p_fstype = FS_BSDFFS; } /* Clear "extended" partition info, tentatively */ for (i = 0; i < SUNXPART; i++) { npp = &lp->d_partitions[i+8]; DL_SETPOFFSET(npp, 0); DL_SETPSIZE(npp, 0); npp->p_fstype = FS_UNUSED; } /* Check to see if there's an "extended" partition table * SL_XPMAG partitions had checksums up to just before the * (new) sl_types variable, while SL_XPMAGTYP partitions have * checksums up to the just before the (new) sl_xxx1 variable. */ if ((sl->sl_xpmag == SL_XPMAG && sun_extended_sum(sl, &sl->sl_types) == sl->sl_xpsum) || (sl->sl_xpmag == SL_XPMAGTYP && sun_extended_sum(sl, &sl->sl_xxx1) == sl->sl_xpsum)) { /* * There is. Copy over the "extended" partitions. * This code parallels the loop for partitions a-h. */ for (i = 0; i < SUNXPART; i++) { spp = &sl->sl_xpart[i]; npp = &lp->d_partitions[i+8]; DL_SETPOFFSET(npp, spp->sdkp_cyloffset); DL_SETPSIZE(npp, spp->sdkp_nsectors); if (DL_GETPSIZE(npp) == 0) { npp->p_fstype = FS_UNUSED; continue; } npp->p_fstype = sun_fstypes[i+8]; if (npp->p_fstype == FS_BSDFFS) { npp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(2048, 8); npp->p_cpg = 16; } } if (sl->sl_xpmag == SL_XPMAGTYP) { for (i = 0; i < MAXPARTITIONS; i++) { npp = &lp->d_partitions[i]; npp->p_fstype = sl->sl_types[i]; npp->p_fragblock = sl->sl_fragblock[i]; npp->p_cpg = sl->sl_cpg[i]; } } } lp->d_checksum = 0; lp->d_checksum = dkcksum(lp); return (checkdisklabel(lp, lp, 0, DL_GETDSIZE(lp))); }
/* * sdstart looks to see if there is a buf waiting for the device * and that the device is not already busy. If both are true, * It dequeues the buf and creates a scsi command to perform the * transfer in the buf. The transfer request will call scsi_done * on completion, which will in turn call this routine again * so that the next queued transfer is performed. * The bufs are queued by the strategy routine (sdstrategy) * * This routine is also called after other non-queued requests * have been made of the scsi driver, to ensure that the queue * continues to be drained. */ void sdstart(struct scsi_xfer *xs) { struct scsi_link *link = xs->sc_link; struct sd_softc *sc = link->device_softc; struct buf *bp; u_int64_t secno; int nsecs; int read; struct partition *p; if (sc->flags & SDF_DYING) { scsi_xs_put(xs); return; } if ((link->flags & SDEV_MEDIA_LOADED) == 0) { bufq_drain(&sc->sc_bufq); scsi_xs_put(xs); return; } bp = bufq_dequeue(&sc->sc_bufq); if (bp == NULL) { scsi_xs_put(xs); return; } secno = DL_BLKTOSEC(sc->sc_dk.dk_label, bp->b_blkno); p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; secno += DL_GETPOFFSET(p); nsecs = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize); read = bp->b_flags & B_READ; /* * Fill out the scsi command. If the transfer will * fit in a "small" cdb, use it. */ if (!(link->flags & SDEV_ATAPI) && !(link->quirks & SDEV_ONLYBIG) && ((secno & 0x1fffff) == secno) && ((nsecs & 0xff) == nsecs)) sd_cmd_rw6(xs, read, secno, nsecs); else if (((secno & 0xffffffff) == secno) && ((nsecs & 0xffff) == nsecs)) sd_cmd_rw10(xs, read, secno, nsecs); else if (((secno & 0xffffffff) == secno) && ((nsecs & 0xffffffff) == nsecs)) sd_cmd_rw12(xs, read, secno, nsecs); else sd_cmd_rw16(xs, read, secno, nsecs); xs->flags |= (read ? SCSI_DATA_IN : SCSI_DATA_OUT); xs->timeout = 60000; xs->data = bp->b_data; xs->datalen = bp->b_bcount; xs->done = sd_buf_done; xs->cookie = bp; xs->bp = bp; /* Instrumentation. */ disk_busy(&sc->sc_dk); /* Mark disk as dirty. */ if (!read) sc->flags |= SDF_DIRTY; scsi_xs_exec(xs); /* move onto the next io */ if (ISSET(sc->flags, SDF_WAITING)) CLR(sc->flags, SDF_WAITING); else if (bufq_peek(&sc->sc_bufq)) scsi_xsh_add(&sc->sc_xsh); }
void bootstrap(int devfd, char *dev, char *bootfile) { struct disklabel dl; struct disklabel *lp; struct partition *pp; char *boot, *p, part; size_t bootsize; size_t bootsec; struct stat sb; int fd, i; /* * Install bootstrap code onto the given disk, preserving the * existing disklabel. */ /* Read disklabel from disk. */ if (ioctl(devfd, DIOCGDINFO, &dl) == -1) err(1, "disklabel"); if (dl.d_secsize == 0) { warnx("disklabel has sector size of 0, assuming %d", DEV_BSIZE); dl.d_secsize = DEV_BSIZE; } /* Read bootstrap file. */ if (verbose) fprintf(stderr, "reading bootstrap from %s\n", bootfile); fd = open(bootfile, O_RDONLY); if (fd < 0) err(1, "open %s", bootfile); if (fstat(fd, &sb) != 0) err(1, "fstat %s", bootfile); bootsec = howmany((ssize_t)sb.st_size, dl.d_secsize); bootsize = bootsec * dl.d_secsize; if (verbose) fprintf(stderr, "bootstrap is %zu bytes " "(%zu sectors @ %u bytes = %zu bytes)\n", (ssize_t)sb.st_size, bootsec, dl.d_secsize, bootsize); boot = calloc(1, bootsize); if (boot == NULL) err(1, "calloc"); if (read(fd, boot, bootsize) != (ssize_t)sb.st_size) err(1, "read"); close(fd); /* * Check that the bootstrap will fit - partitions must not overlap, * or if they do, the partition type must be either FS_BOOT or * FS_UNUSED. The 'c' partition will always overlap and is ignored. */ if (verbose) fprintf(stderr, "ensuring used partitions do not overlap " "with bootstrap sectors 0-%zu\n", bootsec); for (i = 0; i < dl.d_npartitions; i++) { part = 'a' + i; pp = &dl.d_partitions[i]; if (i == RAW_PART) continue; if (DL_GETPSIZE(pp) == 0) continue; if ((u_int64_t)bootsec <= DL_GETPOFFSET(pp)) continue; switch (pp->p_fstype) { case FS_BOOT: break; case FS_UNUSED: warnx("bootstrap overlaps with unused partition %c", part); break; default: errx(1, "bootstrap overlaps with partition %c", part); } } /* Make sure the bootstrap has left space for the disklabel. */ lp = (struct disklabel *)(boot + (LABELSECTOR * dl.d_secsize) + LABELOFFSET); for (i = 0, p = (char *)lp; i < (int)sizeof(*lp); i++) if (p[i] != 0) errx(1, "bootstrap has data in disklabel area"); /* Patch the disklabel into the bootstrap code. */ memcpy(lp, &dl, sizeof(dl)); /* Write the bootstrap out to the disk. */ if (lseek(devfd, 0, SEEK_SET) != 0) err(1, "lseek"); if (verbose) fprintf(stderr, "%s bootstrap to disk\n", (nowrite ? "would write" : "writing")); if (nowrite) return; if (write(devfd, boot, bootsize) != (ssize_t)bootsize) err(1, "write"); }
/* * Dump core after a system crash. */ int wddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) { struct wd_softc *wd; /* disk unit to do the I/O */ struct disklabel *lp; /* disk's disklabel */ int unit, part; int nblks; /* total number of sectors left to write */ int nwrt; /* sectors to write with current i/o. */ int err; char errbuf[256]; /* Check if recursive dump; if so, punt. */ if (wddoingadump) return EFAULT; wddoingadump = 1; unit = DISKUNIT(dev); wd = wdlookup(unit); if (wd == NULL) return ENXIO; part = DISKPART(dev); /* Make sure it was initialized. */ if (wd->drvp->state < READY) return ENXIO; /* Convert to disk sectors. Request must be a multiple of size. */ lp = wd->sc_dk.dk_label; if ((size % lp->d_secsize) != 0) return EFAULT; nblks = size / lp->d_secsize; blkno = blkno / (lp->d_secsize / DEV_BSIZE); /* Check transfer bounds against partition size. */ if ((blkno < 0) || ((blkno + nblks) > DL_GETPSIZE(&lp->d_partitions[part]))) return EINVAL; /* Offset block number to start of partition. */ blkno += DL_GETPOFFSET(&lp->d_partitions[part]); /* Recalibrate, if first dump transfer. */ if (wddumprecalibrated == 0) { wddumpmulti = wd->sc_multi; wddumprecalibrated = 1; wd->drvp->state = RECAL; } while (nblks > 0) { nwrt = min(nblks, wddumpmulti); wd->sc_wdc_bio.blkno = blkno; wd->sc_wdc_bio.flags = ATA_POLL; if (wd->sc_flags & WDF_LBA48) wd->sc_wdc_bio.flags |= ATA_LBA48; if (wd->sc_flags & WDF_LBA) wd->sc_wdc_bio.flags |= ATA_LBA; wd->sc_wdc_bio.bcount = nwrt * lp->d_secsize; wd->sc_wdc_bio.databuf = va; wd->sc_wdc_bio.wd = wd; #ifndef WD_DUMP_NOT_TRUSTED switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) { case WDC_TRY_AGAIN: panic("wddump: try again"); break; case WDC_QUEUED: panic("wddump: polled command has been queued"); break; case WDC_COMPLETE: break; } switch(wd->sc_wdc_bio.error) { case TIMEOUT: printf("wddump: device timed out"); err = EIO; break; case ERR_DF: printf("wddump: drive fault"); err = EIO; break; case ERR_DMA: printf("wddump: DMA error"); err = EIO; break; case ERROR: errbuf[0] = '\0'; ata_perror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf, sizeof errbuf); printf("wddump: %s", errbuf); err = EIO; break; case NOERROR: err = 0; break; default: panic("wddump: unknown error type"); } if (err != 0) { printf("\n"); return err; } #else /* WD_DUMP_NOT_TRUSTED */ /* Let's just talk about this first... */ printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n", unit, va, cylin, head, sector); delay(500 * 1000); /* half a second */ #endif /* update block count */ nblks -= nwrt; blkno += nwrt; va += nwrt * lp->d_secsize; } wddoingadump = 0; return 0; }
/* * Read information about /boot's inode, then put this and filesystem * parameters from the superblock into pbr_symbols. */ static int getbootparams(char *boot, int devfd, struct disklabel *dl) { int fd; struct stat statbuf, sb; struct statfs statfsbuf; struct partition *pp; struct fs *fs; char *buf; u_int blk, *ap; struct ufs1_dinode *ip1; struct ufs2_dinode *ip2; int ndb; int mib[3]; size_t size; dev_t dev; int skew; /* * Open 2nd-level boot program and record enough details about * where it is on the filesystem represented by `devfd' * (inode block, offset within that block, and various filesystem * parameters essentially taken from the superblock) for biosboot * to be able to load it later. */ /* Make sure the (probably new) boot file is on disk. */ sync(); sleep(1); if ((fd = open(boot, O_RDONLY)) < 0) err(1, "open: %s", boot); if (fstatfs(fd, &statfsbuf) != 0) err(1, "statfs: %s", boot); if (strncmp(statfsbuf.f_fstypename, "ffs", MFSNAMELEN) && strncmp(statfsbuf.f_fstypename, "ufs", MFSNAMELEN) ) errx(1, "%s: not on an FFS filesystem", boot); #if 0 if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) errx(1, "read: %s", boot); if (!IS_ELF(eh)) { errx(1, "%s: bad magic: 0x%02x%02x%02x%02x", boot, eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1], eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]); } #endif if (fsync(fd) != 0) err(1, "fsync: %s", boot); if (fstat(fd, &statbuf) != 0) err(1, "fstat: %s", boot); if (fstat(devfd, &sb) != 0) err(1, "fstat: %s", realdev); /* Check devices. */ mib[0] = CTL_MACHDEP; mib[1] = CPU_CHR2BLK; mib[2] = sb.st_rdev; size = sizeof(dev); if (sysctl(mib, 3, &dev, &size, NULL, 0) >= 0) { if (statbuf.st_dev / MAXPARTITIONS != dev / MAXPARTITIONS) errx(1, "cross-device install"); } pp = &dl->d_partitions[DISKPART(statbuf.st_dev)]; close(fd); sbread(devfd, DL_SECTOBLK(dl, DL_GETPOFFSET(pp)), &fs); /* Read inode. */ if ((buf = malloc(fs->fs_bsize)) == NULL) err(1, NULL); blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino)); /* * Have the inode. Figure out how many filesystem blocks (not disk * sectors) there are for biosboot to load. */ devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset) + blk, fs->fs_bsize, "inode"); if (fs->fs_magic == FS_UFS2_MAGIC) { ip2 = (struct ufs2_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino); ndb = howmany(ip2->di_size, fs->fs_bsize); ap = (u_int *)ip2->di_db; skew = sizeof(u_int32_t); } else { ip1 = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino); ndb = howmany(ip1->di_size, fs->fs_bsize); ap = (u_int *)ip1->di_db; skew = 0; } if (ndb <= 0) errx(1, "No blocks to load"); /* * Now set the values that will need to go into biosboot * (the partition boot record, a.k.a. the PBR). */ sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16)); sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / dl->d_secsize)); /* * fs_fsbtodb is the shift to convert fs_fsize to DEV_BSIZE. The * ino_to_fsba() return value is the number of fs_fsize units. * Calculate the shift to convert fs_fsize into physical sectors, * which are added to p_offset to get the sector address BIOS * will use. * * N.B.: ASSUMES fs_fsize is a power of 2 of d_secsize. */ sym_set_value(pbr_symbols, "_fsbtodb", ffs(fs->fs_fsize / dl->d_secsize) - 1); if (pp->p_offseth != 0) errx(1, "partition offset too high"); sym_set_value(pbr_symbols, "_p_offset", pp->p_offset); sym_set_value(pbr_symbols, "_inodeblk", ino_to_fsba(fs, statbuf.st_ino)); sym_set_value(pbr_symbols, "_inodedbl", ((((char *)ap) - buf) + INODEOFF)); sym_set_value(pbr_symbols, "_nblocks", ndb); sym_set_value(pbr_symbols, "_blkskew", skew); if (verbose) { fprintf(stderr, "%s is %d blocks x %d bytes\n", boot, ndb, fs->fs_bsize); fprintf(stderr, "fs block shift %u; part offset %llu; " "inode block %lld, offset %u\n", ffs(fs->fs_fsize / dl->d_secsize) - 1, DL_GETPOFFSET(pp), ino_to_fsba(fs, statbuf.st_ino), (unsigned int)((((char *)ap) - buf) + INODEOFF)); fprintf(stderr, "expecting %d-bit fs blocks (skew %d)\n", skew ? 64 : 32, skew); } return 0; }
/* * sdstart looks to see if there is a buf waiting for the device * and that the device is not already busy. If both are true, * It dequeues the buf and creates a scsi command to perform the * transfer in the buf. The transfer request will call scsi_done * on completion, which will in turn call this routine again * so that the next queued transfer is performed. * The bufs are queued by the strategy routine (sdstrategy) * * This routine is also called after other non-queued requests * have been made of the scsi driver, to ensure that the queue * continues to be drained. */ void sdstart(void *v) { struct sd_softc *sc = (struct sd_softc *)v; struct scsi_link *link = sc->sc_link; struct scsi_xfer *xs; struct buf *bp; daddr64_t blkno; int nblks; int read; struct partition *p; int s; if (sc->flags & SDF_DYING) return; SC_DEBUG(link, SDEV_DB2, ("sdstart\n")); mtx_enter(&sc->sc_start_mtx); if (ISSET(sc->flags, SDF_STARTING)) { mtx_leave(&sc->sc_start_mtx); return; } SET(sc->flags, SDF_STARTING); mtx_leave(&sc->sc_start_mtx); CLR(sc->flags, SDF_WAITING); while (!ISSET(sc->flags, SDF_WAITING) && (bp = sd_buf_dequeue(sc)) != NULL) { /* * If the device has become invalid, abort all the * reads and writes until all files have been closed and * re-opened */ if ((link->flags & SDEV_MEDIA_LOADED) == 0) { bp->b_error = EIO; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; s = splbio(); biodone(bp); splx(s); continue; } xs = scsi_xs_get(link, SCSI_NOSLEEP); if (xs == NULL) { sd_buf_requeue(sc, bp); break; } blkno = bp->b_blkno / (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE); p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; blkno += DL_GETPOFFSET(p); nblks = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize); read = bp->b_flags & B_READ; /* * Fill out the scsi command. If the transfer will * fit in a "small" cdb, use it. */ if (!(link->flags & SDEV_ATAPI) && !(link->quirks & SDEV_ONLYBIG) && ((blkno & 0x1fffff) == blkno) && ((nblks & 0xff) == nblks)) sd_cmd_rw6(xs, read, blkno, nblks); else if (((blkno & 0xffffffff) == blkno) && ((nblks & 0xffff) == nblks)) sd_cmd_rw10(xs, read, blkno, nblks); else if (((blkno & 0xffffffff) == blkno) && ((nblks & 0xffffffff) == nblks)) sd_cmd_rw12(xs, read, blkno, nblks); else sd_cmd_rw16(xs, read, blkno, nblks); xs->flags |= (read ? SCSI_DATA_IN : SCSI_DATA_OUT); xs->timeout = 60000; xs->data = bp->b_data; xs->datalen = bp->b_bcount; xs->done = sd_buf_done; xs->cookie = bp; /* Instrumentation. */ disk_busy(&sc->sc_dk); /* Mark disk as dirty. */ if ((bp->b_flags & B_READ) == 0) sc->flags |= SDF_DIRTY; scsi_xs_exec(xs); } mtx_enter(&sc->sc_start_mtx); CLR(sc->flags, SDF_STARTING); mtx_leave(&sc->sc_start_mtx); }
void vndstrategy(struct buf *bp) { int unit = DISKUNIT(bp->b_dev); struct vnd_softc *sc; struct partition *p; off_t off; long origbcount; int s; DNPRINTF(VDB_FOLLOW, "vndstrategy(%p): unit %d\n", bp, unit); if (unit >= numvnd) { bp->b_error = ENXIO; goto bad; } sc = &vnd_softc[unit]; if ((sc->sc_flags & VNF_HAVELABEL) == 0) { bp->b_error = ENXIO; goto bad; } /* * Many of the distrib scripts assume they can issue arbitrary * sized requests to raw vnd devices irrespective of the * emulated disk geometry. * * To continue supporting this, round the block count up to a * multiple of d_secsize for bounds_check_with_label(), and * then restore afterwards. * * We only do this for non-encrypted vnd, because encryption * requires operating on blocks at a time. */ origbcount = bp->b_bcount; if (sc->sc_keyctx == NULL) { u_int32_t secsize = sc->sc_dk.dk_label->d_secsize; bp->b_bcount = ((origbcount + secsize - 1) & ~(secsize - 1)); #ifdef DIAGNOSTIC if (bp->b_bcount != origbcount) { struct proc *pr = curproc; printf("%s: sloppy %s from proc %d (%s): " "blkno %lld bcount %ld\n", sc->sc_dev.dv_xname, (bp->b_flags & B_READ) ? "read" : "write", pr->p_pid, pr->p_comm, (long long)bp->b_blkno, origbcount); } #endif } if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1) { bp->b_resid = bp->b_bcount = origbcount; goto done; } if (origbcount < bp->b_bcount) bp->b_bcount = origbcount; p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; off = DL_GETPOFFSET(p) * sc->sc_dk.dk_label->d_secsize + (u_int64_t)bp->b_blkno * DEV_BSIZE; if (sc->sc_keyctx && !(bp->b_flags & B_READ)) vndencryptbuf(sc, bp, 1); /* * Use IO_NOLIMIT because upper layer has already checked I/O * for limits, so there is no need to do it again. */ bp->b_error = vn_rdwr((bp->b_flags & B_READ) ? UIO_READ : UIO_WRITE, sc->sc_vp, bp->b_data, bp->b_bcount, off, UIO_SYSSPACE, IO_NOLIMIT, sc->sc_cred, &bp->b_resid, curproc); if (bp->b_error) bp->b_flags |= B_ERROR; /* Data in buffer cache needs to be in clear */ if (sc->sc_keyctx) vndencryptbuf(sc, bp, 0); goto done; bad: bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; done: s = splbio(); biodone(bp); splx(s); }
void makedisktab(FILE *f, struct disklabel *lp) { int i; struct partition *pp; if (lp->d_packname[0]) (void)fprintf(f, "%.*s|", (int)sizeof(lp->d_packname), lp->d_packname); if (lp->d_typename[0]) (void)fprintf(f, "%.*s|", (int)sizeof(lp->d_typename), lp->d_typename); (void)fputs("Automatically generated label:\\\n\t:dt=", f); if (lp->d_type < DKMAXTYPES) (void)fprintf(f, "%s:", dktypenames[lp->d_type]); else (void)fprintf(f, "unknown%d:", lp->d_type); (void)fprintf(f, "se#%u:", lp->d_secsize); (void)fprintf(f, "ns#%u:", lp->d_nsectors); (void)fprintf(f, "nt#%u:", lp->d_ntracks); (void)fprintf(f, "nc#%u:", lp->d_ncylinders); (void)fprintf(f, "sc#%u:", lp->d_secpercyl); (void)fprintf(f, "su#%llu:", DL_GETDSIZE(lp)); /* * XXX We do not print have disktab information yet for * XXX DL_GETBSTART DL_GETBEND */ for (i = 0; i < NDDATA; i++) if (lp->d_drivedata[i]) (void)fprintf(f, "d%d#%u", i, lp->d_drivedata[i]); pp = lp->d_partitions; for (i = 0; i < lp->d_npartitions; i++, pp++) { if (DL_GETPSIZE(pp)) { char c = 'a' + i; (void)fprintf(f, "\\\n\t:"); (void)fprintf(f, "p%c#%llu:", c, DL_GETPSIZE(pp)); (void)fprintf(f, "o%c#%llu:", c, DL_GETPOFFSET(pp)); if (pp->p_fstype != FS_UNUSED) { if (pp->p_fstype < FSMAXTYPES) (void)fprintf(f, "t%c=%s:", c, fstypenames[pp->p_fstype]); else (void)fprintf(f, "t%c=unknown%d:", c, pp->p_fstype); } switch (pp->p_fstype) { case FS_UNUSED: break; case FS_BSDFFS: (void)fprintf(f, "b%c#%u:", c, DISKLABELV1_FFS_BSIZE(pp->p_fragblock)); (void)fprintf(f, "f%c#%u:", c, DISKLABELV1_FFS_FSIZE(pp->p_fragblock)); break; default: break; } } } (void)fputc('\n', f); (void)fflush(f); }
/* * dump all of physical memory into the partition specified, starting * at offset 'dumplo' into the partition. */ int sddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) { struct sd_softc *sc; /* disk unit to do the I/O */ struct disklabel *lp; /* disk's disklabel */ int unit, part; u_int32_t sectorsize; /* size of a disk sector */ u_int64_t nsects; /* number of sectors in partition */ u_int64_t sectoff; /* sector offset of partition */ u_int64_t totwrt; /* total number of sectors left to write */ u_int32_t nwrt; /* current number of sectors to write */ struct scsi_xfer *xs; /* ... convenience */ int rv; /* Check if recursive dump; if so, punt. */ if (sddoingadump) return EFAULT; if (blkno < 0) return EINVAL; /* Mark as active early. */ sddoingadump = 1; unit = DISKUNIT(dev); /* Decompose unit & partition. */ part = DISKPART(dev); /* Check for acceptable drive number. */ if (unit >= sd_cd.cd_ndevs || (sc = sd_cd.cd_devs[unit]) == NULL) return ENXIO; /* * XXX Can't do this check, since the media might have been * XXX marked `invalid' by successful unmounting of all * XXX filesystems. */ #if 0 /* Make sure it was initialized. */ if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED) return ENXIO; #endif /* Convert to disk sectors. Request must be a multiple of size. */ lp = sc->sc_dk.dk_label; sectorsize = lp->d_secsize; if ((size % sectorsize) != 0) return EFAULT; if ((blkno % DL_BLKSPERSEC(lp)) != 0) return EFAULT; totwrt = size / sectorsize; blkno = DL_BLKTOSEC(lp, blkno); nsects = DL_GETPSIZE(&lp->d_partitions[part]); sectoff = DL_GETPOFFSET(&lp->d_partitions[part]); /* Check transfer bounds against partition size. */ if ((blkno + totwrt) > nsects) return EINVAL; /* Offset block number to start of partition. */ blkno += sectoff; while (totwrt > 0) { if (totwrt > UINT32_MAX) nwrt = UINT32_MAX; else nwrt = totwrt; #ifndef SD_DUMP_NOT_TRUSTED xs = scsi_xs_get(sc->sc_link, SCSI_NOSLEEP); if (xs == NULL) return (ENOMEM); xs->timeout = 10000; xs->flags |= SCSI_DATA_OUT; xs->data = va; xs->datalen = nwrt * sectorsize; sd_cmd_rw10(xs, 0, blkno, nwrt); /* XXX */ rv = scsi_xs_sync(xs); scsi_xs_put(xs); if (rv != 0) return (ENXIO); #else /* SD_DUMP_NOT_TRUSTED */ /* Let's just talk about this first... */ printf("sd%d: dump addr 0x%x, blk %lld\n", unit, va, (long long)blkno); delay(500 * 1000); /* half a second */ #endif /* SD_DUMP_NOT_TRUSTED */ /* update block count */ totwrt -= nwrt; blkno += nwrt; va += sectorsize * nwrt; } sddoingadump = 0; return (0); }
int main(int argc, char *argv[]) { int c, devfd; char *protostore; long protosize; struct stat disksb, bootsb; struct disklabel dl; daddr64_t partoffset; #define BBPAD 0x1e0 struct bb { char bb_pad[BBPAD]; /* disklabel lives in here, actually */ long bb_secsize; /* size of secondary boot block */ long bb_secstart; /* start of secondary boot block */ long bb_flags; /* unknown; always zero */ long bb_cksum; /* checksum of the boot block, as longs. */ } bb; long *lp, *ep; while ((c = getopt(argc, argv, "vns:e:")) != -1) { switch (c) { case 'n': /* Do not actually write the bootblock to disk */ nowrite = 1; break; case 'v': /* Chat */ verbose = 1; break; case 's': isofsblk = atoi(optarg); break; case 'e': isofseblk = atoi(optarg); break; default: usage(); } } if (argc - optind < 3) usage(); boot = argv[optind]; proto = argv[optind + 1]; dev = argv[optind + 2]; if (verbose) { (void)printf("boot: %s\n", boot); (void)printf("proto: %s\n", proto); (void)printf("device: %s\n", dev); } /* Load proto blocks into core */ if ((protostore = loadprotoblocks(proto, &protosize)) == NULL) exit(1); /* Open and check raw disk device */ if ((devfd = opendev(dev, O_RDONLY, OPENDEV_PART, &dev)) < 0) err(1, "open: %s", dev); if (fstat(devfd, &disksb) == -1) err(1, "fstat: %s", dev); if (!S_ISCHR(disksb.st_mode)) errx(1, "%s must be a character device node", dev); if ((minor(disksb.st_rdev) % getmaxpartitions()) != getrawpartition()) errx(1, "%s must be the raw partition", dev); /* Extract and load block numbers */ if (stat(boot, &bootsb) == -1) err(1, "stat: %s", boot); if (!S_ISREG(bootsb.st_mode)) errx(1, "%s must be a regular file", boot); if ((minor(disksb.st_rdev) / getmaxpartitions()) != (minor(bootsb.st_dev) / getmaxpartitions())) errx(1, "%s must be somewhere on %s", boot, dev); /* * Find the offset of the secondary boot block's partition * into the disk. If disklabels not supported, assume zero. */ if (ioctl(devfd, DIOCGDINFO, &dl) != -1) { partoffset = DL_GETPOFFSET(&dl.d_partitions[minor(bootsb.st_dev) % getmaxpartitions()]); } else { if (errno != ENOTTY) err(1, "read disklabel: %s", dev); warnx("couldn't read label from %s, using part offset of 0", dev); partoffset = 0; } if (verbose) (void)printf("%s partition offset = 0x%lx\n", boot, partoffset); /* Sync filesystems (make sure boot's block numbers are stable) */ sync(); sleep(2); sync(); sleep(2); if (loadblocknums(boot, devfd, partoffset) != 0) exit(1); (void)close(devfd); if (nowrite) return 0; #if 0 /* Write patched proto bootblocks into the superblock */ if (protosize > SBSIZE - DEV_BSIZE) errx(1, "proto bootblocks too big"); #endif if ((devfd = opendev(dev, O_RDWR, OPENDEV_PART, &dev)) < 0) err(1, "open: %s", dev); if (lseek(devfd, DEV_BSIZE, SEEK_SET) != DEV_BSIZE) err(1, "lseek bootstrap"); if (write(devfd, protostore, protosize) != protosize) err(1, "write bootstrap"); if (lseek(devfd, 0, SEEK_SET) != 0) err(1, "lseek label"); if (read(devfd, &bb, sizeof (bb)) != sizeof (bb)) err(1, "read label"); bb.bb_secsize = 15; bb.bb_secstart = 1; bb.bb_flags = 0; bb.bb_cksum = 0; for (lp = (long *)&bb, ep = &bb.bb_cksum; lp < ep; lp++) bb.bb_cksum += *lp; if (lseek(devfd, 0, SEEK_SET) != 0) err(1, "lseek label 2"); if (write(devfd, &bb, sizeof bb) != sizeof bb) err(1, "write label "); (void)close(devfd); return 0; }