/* * Given a SunOS disk label, set lp to a BSD disk label. * The BSD label is cleared out before this is called. */ static int disklabel_sun_to_bsd(struct sun_disklabel *sl, struct disklabel *lp) { struct sun_preamble *preamble = (struct sun_preamble *)sl; struct sun_partinfo *ppp; struct sun_dkpart *spp; struct partition *npp; u_short cksum = 0, *sp1, *sp2; int i, secpercyl; /* Verify the XOR check. */ sp1 = (u_short *)sl; sp2 = (u_short *)(sl + 1); while (sp1 < sp2) cksum ^= *sp1++; if (cksum != 0) return (EINVAL); /* SunOS 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(lp->d_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]; DL_SETPOFFSET(npp, spp->sdkp_cyloffset * secpercyl); 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; } } } /* 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. * Also, disklabels created prior to the addition of sl_uid will * have a checksum to just before the sl_uid 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_uid) == 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 * secpercyl); 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]; } } } else if (preamble->sl_nparts <= 8) { /* * A more traditional Sun label. Recognise certain filesystem * types from it, if they are available. */ i = preamble->sl_nparts; if (i == 0) i = 8; npp = &lp->d_partitions[i-1]; ppp = &preamble->sl_part[i-1]; for (; i > 0; i--, npp--, ppp--) { if (npp->p_size == 0) continue; if ((ppp->spi_tag == 0) && (ppp->spi_flag == 0)) continue; switch (ppp->spi_tag) { case SPTAG_SUNOS_ROOT: case SPTAG_SUNOS_USR: case SPTAG_SUNOS_VAR: case SPTAG_SUNOS_HOME: npp->p_fstype = FS_BSDFFS; npp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(2048, 8); npp->p_cpg = 16; break; case SPTAG_LINUX_EXT2: npp->p_fstype = FS_EXT2FS; break; default: /* FS_SWAP for _SUNOS_SWAP and _LINUX_SWAP? */ npp->p_fstype = FS_UNUSED; break; } } } lp->d_checksum = 0; lp->d_checksum = dkcksum(lp); return (checkdisklabel(lp, lp, 0, DL_GETDSIZE(lp))); }
/* * 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); }
/* * 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); }
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); }
/* * 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))); }
struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) { struct exfat_dev* dev; struct stat stbuf; #ifdef USE_UBLIO struct ublio_param up; #endif dev = malloc(sizeof(struct exfat_dev)); if (dev == NULL) { exfat_error("failed to allocate memory for device structure"); return NULL; } switch (mode) { case EXFAT_MODE_RO: dev->fd = open_ro(spec); if (dev->fd == -1) { free(dev); exfat_error("failed to open '%s' in read-only mode: %s", spec, strerror(errno)); return NULL; } dev->mode = EXFAT_MODE_RO; break; case EXFAT_MODE_RW: dev->fd = open_rw(spec); if (dev->fd == -1) { free(dev); exfat_error("failed to open '%s' in read-write mode: %s", spec, strerror(errno)); return NULL; } dev->mode = EXFAT_MODE_RW; break; case EXFAT_MODE_ANY: dev->fd = open_rw(spec); if (dev->fd != -1) { dev->mode = EXFAT_MODE_RW; break; } dev->fd = open_ro(spec); if (dev->fd != -1) { dev->mode = EXFAT_MODE_RO; exfat_warn("'%s' is write-protected, mounting read-only", spec); break; } free(dev); exfat_error("failed to open '%s': %s", spec, strerror(errno)); return NULL; } if (fstat(dev->fd, &stbuf) != 0) { close(dev->fd); free(dev); exfat_error("failed to fstat '%s'", spec); return NULL; } if (!S_ISBLK(stbuf.st_mode) && !S_ISCHR(stbuf.st_mode) && !S_ISREG(stbuf.st_mode)) { close(dev->fd); free(dev); exfat_error("'%s' is neither a device, nor a regular file", spec); return NULL; } #if defined(__APPLE__) if (!S_ISREG(stbuf.st_mode)) { uint32_t block_size = 0; uint64_t blocks = 0; if (ioctl(dev->fd, DKIOCGETBLOCKSIZE, &block_size) != 0) { close(dev->fd); free(dev); exfat_error("failed to get block size"); return NULL; } if (ioctl(dev->fd, DKIOCGETBLOCKCOUNT, &blocks) != 0) { close(dev->fd); free(dev); exfat_error("failed to get blocks count"); return NULL; } dev->size = blocks * block_size; } else #elif defined(__OpenBSD__) if (!S_ISREG(stbuf.st_mode)) { struct disklabel lab; struct partition* pp; char* partition; if (ioctl(dev->fd, DIOCGDINFO, &lab) == -1) { close(dev->fd); free(dev); exfat_error("failed to get disklabel"); return NULL; } /* Don't need to check that partition letter is valid as we won't get this far otherwise. */ partition = strchr(spec, '\0') - 1; pp = &(lab.d_partitions[*partition - 'a']); dev->size = DL_GETPSIZE(pp) * lab.d_secsize; if (pp->p_fstype != FS_NTFS) exfat_warn("partition type is not 0x07 (NTFS/exFAT); " "you can fix this with fdisk(8)"); } else #endif { /* works for Linux, FreeBSD, Solaris */ dev->size = exfat_seek(dev, 0, SEEK_END); if (dev->size <= 0) { close(dev->fd); free(dev); exfat_error("failed to get size of '%s'", spec); return NULL; } if (exfat_seek(dev, 0, SEEK_SET) == -1) { close(dev->fd); free(dev); exfat_error("failed to seek to the beginning of '%s'", spec); return NULL; } } #ifdef USE_UBLIO memset(&up, 0, sizeof(struct ublio_param)); up.up_blocksize = 256 * 1024; up.up_items = 64; up.up_grace = 32; up.up_priv = &dev->fd; dev->pos = 0; dev->ufh = ublio_open(&up); if (dev->ufh == NULL) { close(dev->fd); free(dev); exfat_error("failed to initialize ublio"); return NULL; } #endif return dev; }
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 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); }
/* * 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; }
int main(int argc, char *argv[]) { int ch; struct partition *pp; struct disklabel *lp; struct partition oldpartition; struct stat st; struct statfs *mp; struct rlimit rl; int fsi = -1, fso, len, n, maxpartitions; char *cp = NULL, *s1, *s2, *special, *opstring, *realdev; char *fstype = NULL; char **saveargv = argv; int ffsflag = 1; const char *errstr; long long fssize_input = 0; int fssize_usebytes = 0; u_int64_t nsecs; getphysmem(); maxpartitions = getmaxpartitions(); if (maxpartitions > 26) fatal("insane maxpartitions value %d", maxpartitions); opstring = "NO:S:T:b:c:e:f:g:h:i:m:o:qs:t:"; while ((ch = getopt(argc, argv, opstring)) != -1) { switch (ch) { case 'N': Nflag = 1; break; case 'O': Oflag = strtonum(optarg, 0, 2, &errstr); if (errstr) fatal("%s: invalid ffs version", optarg); break; case 'S': if (scan_scaled(optarg, §orsize) == -1 || sectorsize <= 0 || (sectorsize % DEV_BSIZE)) fatal("sector size invalid: %s", optarg); break; case 'T': disktype = optarg; break; case 'b': bsize = strtonum(optarg, MINBSIZE, MAXBSIZE, &errstr); if (errstr) fatal("block size is %s: %s", errstr, optarg); break; case 'c': maxfrgspercg = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("fragments per cylinder group is %s: %s", errstr, optarg); break; case 'e': maxbpg = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("blocks per file in a cylinder group is" " %s: %s", errstr, optarg); break; case 'f': fsize = strtonum(optarg, MINBSIZE / MAXFRAG, MAXBSIZE, &errstr); if (errstr) fatal("fragment size is %s: %s", errstr, optarg); break; case 'g': avgfilesize = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("average file size is %s: %s", errstr, optarg); break; case 'h': avgfilesperdir = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("average files per dir is %s: %s", errstr, optarg); break; case 'i': density = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("bytes per inode is %s: %s", errstr, optarg); break; case 'm': minfree = strtonum(optarg, 0, 99, &errstr); if (errstr) fatal("free space %% is %s: %s", errstr, optarg); break; case 'o': if (strcmp(optarg, "space") == 0) reqopt = opt = FS_OPTSPACE; else if (strcmp(optarg, "time") == 0) reqopt = opt = FS_OPTTIME; else fatal("%s: unknown optimization preference: " "use `space' or `time'.", optarg); break; case 'q': quiet = 1; break; case 's': if (scan_scaled(optarg, &fssize_input) == -1 || fssize_input == 0) fatal("file system size invalid: %s", optarg); fssize_usebytes = 0; /* in case of multiple -s */ for (s1 = optarg; *s1 != '\0'; s1++) if (isalpha((unsigned char)*s1)) { fssize_usebytes = 1; break; } break; case 't': fstype = optarg; if (strcmp(fstype, "ffs")) ffsflag = 0; break; case '?': default: usage(); } if (!ffsflag) break; } argc -= optind; argv += optind; if (ffsflag && argc != 1) usage(); special = argv[0]; char execname[MAXPATHLEN], name[MAXPATHLEN]; if (fstype == NULL) fstype = readlabelfs(special, 0); if (fstype != NULL && strcmp(fstype, "ffs")) { snprintf(name, sizeof name, "newfs_%s", fstype); saveargv[0] = name; snprintf(execname, sizeof execname, "%s/newfs_%s", _PATH_SBIN, fstype); (void)execv(execname, saveargv); snprintf(execname, sizeof execname, "%s/newfs_%s", _PATH_USRSBIN, fstype); (void)execv(execname, saveargv); err(1, "%s not found", name); } if (Nflag) { fso = -1; } else { fso = opendev(special, O_WRONLY, 0, &realdev); if (fso < 0) fatal("%s: %s", special, strerror(errno)); special = realdev; /* Bail if target special is mounted */ n = getmntinfo(&mp, MNT_NOWAIT); if (n == 0) fatal("%s: getmntinfo: %s", special, strerror(errno)); len = sizeof(_PATH_DEV) - 1; s1 = special; if (strncmp(_PATH_DEV, s1, len) == 0) s1 += len; while (--n >= 0) { s2 = mp->f_mntfromname; if (strncmp(_PATH_DEV, s2, len) == 0) { s2 += len - 1; *s2 = 'r'; } if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) fatal("%s is mounted on %s", special, mp->f_mntonname); ++mp; } } fsi = opendev(special, O_RDONLY, 0, NULL); if (fsi < 0) fatal("%s: %s", special, strerror(errno)); if (fstat(fsi, &st) < 0) fatal("%s: %s", special, strerror(errno)); if (S_ISBLK(st.st_mode)) fatal("%s: block device", special); if (!S_ISCHR(st.st_mode)) warnx("%s: not a character-special device", special); if (*argv[0] == '\0') fatal("empty partition name supplied"); cp = argv[0] + strlen(argv[0]) - 1; if ((*cp < 'a' || *cp > ('a' + maxpartitions - 1)) && !isdigit((unsigned char)*cp)) fatal("%s: can't figure out file system partition", argv[0]); lp = getdisklabel(special, fsi); if (pledge("stdio disklabel tty", NULL) == -1) err(1, "pledge"); if (isdigit((unsigned char)*cp)) pp = &lp->d_partitions[0]; else pp = &lp->d_partitions[*cp - 'a']; if (DL_GETPSIZE(pp) == 0) fatal("%s: `%c' partition is unavailable", argv[0], *cp); if (pp->p_fstype == FS_BOOT) fatal("%s: `%c' partition overlaps boot program", argv[0], *cp); havelabel: if (sectorsize == 0) { sectorsize = lp->d_secsize; if (sectorsize <= 0) fatal("%s: no default sector size", argv[0]); } if (fssize_input < 0) { #if 1 fatal("-s < 0 not yet implemented"); #else long long gap; /* leave gap at the end of partition */ fssize_input = -fssize_input; if (fssize_usebytes) { gap = (daddr_t)fssize_input / (daddr_t)sectorsize; if ((daddr_t)fssize_input % (daddr_t)sectorsize != 0) gap++; } else gap = fssize_input; if (gap >= DL_GETPSIZE(pp)) fatal("%s: requested gap of %lld sectors on partition " "'%c' is too big", argv[0], gap, *cp); nsecs = DL_GETPSIZE(pp) - gap; #endif } else { if (fssize_usebytes) { nsecs = fssize_input / sectorsize; if (fssize_input % sectorsize != 0) nsecs++; } else if (fssize_input == 0) nsecs = DL_GETPSIZE(pp); else nsecs = fssize_input; } if (nsecs > DL_GETPSIZE(pp)) fatal("%s: maximum file system size on the `%c' partition is " "%llu sectors", argv[0], *cp, DL_GETPSIZE(pp)); /* Can't use DL_SECTOBLK() because sectorsize may not be from label! */ fssize = nsecs * (sectorsize / DEV_BSIZE); if (fsize == 0) { fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); if (fsize <= 0) fsize = MAX(DFL_FRAGSIZE, lp->d_secsize); } if (bsize == 0) { bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock); if (bsize <= 0) bsize = MIN(DFL_BLKSIZE, 8 * fsize); } if (density == 0) density = NFPI * fsize; if (minfree < MINFREE && opt != FS_OPTSPACE && reqopt == -1) { warnx("warning: changing optimization to space " "because minfree is less than %d%%\n", MINFREE); opt = FS_OPTSPACE; } if (maxbpg == 0) { if (Oflag <= 1) maxbpg = MAXBLKPG_FFS1(bsize); else maxbpg = MAXBLKPG_FFS2(bsize); } oldpartition = *pp; mkfs(pp, special, fsi, fso); if (!Nflag && memcmp(pp, &oldpartition, sizeof(oldpartition))) rewritelabel(special, fso, lp); if (!Nflag) close(fso); close(fsi); exit(0); }
void vdsp_open(void *arg1) { struct vdsp_softc *sc = arg1; struct proc *p = curproc; struct vd_attr_info ai; if (sc->sc_vp == NULL) { struct nameidata nd; struct vattr va; struct partinfo pi; const char *name; dev_t dev; int error; name = mdesc_get_prop_str(sc->sc_idx, "vds-block-device"); if (name == NULL) return; NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p); error = vn_open(&nd, FREAD | FWRITE, 0); if (error) { printf("VOP_OPEN: %s, %d\n", name, error); return; } if (nd.ni_vp->v_type == VBLK) { dev = nd.ni_vp->v_rdev; error = (*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART, (caddr_t)&pi, FREAD, curproc); if (error) printf("DIOCGPART: %s, %d\n", name, error); sc->sc_vdisk_block_size = pi.disklab->d_secsize; sc->sc_vdisk_size = DL_GETPSIZE(pi.part); } else { error = VOP_GETATTR(nd.ni_vp, &va, p->p_ucred, p); if (error) printf("VOP_GETATTR: %s, %d\n", name, error); sc->sc_vdisk_block_size = DEV_BSIZE; sc->sc_vdisk_size = va.va_size / DEV_BSIZE; } VOP_UNLOCK(nd.ni_vp, 0, p); sc->sc_vp = nd.ni_vp; vdsp_readlabel(sc); } bzero(&ai, sizeof(ai)); ai.tag.type = VIO_TYPE_CTRL; ai.tag.stype = VIO_SUBTYPE_ACK; ai.tag.stype_env = VIO_ATTR_INFO; ai.tag.sid = sc->sc_local_sid; ai.xfer_mode = sc->sc_xfer_mode; ai.vd_type = VD_DISK_TYPE_DISK; if (sc->sc_major > 1 || sc->sc_minor >= 1) { if (vdsp_is_iso(sc)) ai.vd_mtype = VD_MEDIA_TYPE_CD; else ai.vd_mtype = VD_MEDIA_TYPE_FIXED; } ai.vdisk_block_size = sc->sc_vdisk_block_size; ai.operations = VD_OP_MASK; ai.vdisk_size = sc->sc_vdisk_size; ai.max_xfer_sz = MAXPHYS / sc->sc_vdisk_block_size; vdsp_sendmsg(sc, &ai, sizeof(ai), 1); }
/* Configure a single disk in the array. */ int rf_ConfigureDisk(RF_Raid_t *raidPtr, char *buf, RF_RaidDisk_t *diskPtr, RF_RowCol_t row, RF_RowCol_t col) { char *p; int retcode; struct partinfo dpart; struct vnode *vp; struct vattr va; struct proc *proc; int error; retcode = 0; p = rf_find_non_white(buf); if (*buf != '\0' && p[strlen(p) - 1] == '\n') { /* Strip off the newline. */ p[strlen(p) - 1] = '\0'; } (void) strlcpy(diskPtr->devname, p, sizeof diskPtr->devname); proc = raidPtr->engine_thread; /* Let's start by claiming the component is fine and well... */ diskPtr->status = rf_ds_optimal; raidPtr->raid_cinfo[row][col].ci_vp = NULL; raidPtr->raid_cinfo[row][col].ci_dev = 0; error = raidlookup(diskPtr->devname, curproc, &vp); if (error) { printf("raidlookup on device: %s failed !\n", diskPtr->devname); if (error == ENXIO) { /* The component isn't there... Must be dead :-( */ diskPtr->status = rf_ds_failed; } else { return (error); } } if (diskPtr->status == rf_ds_optimal) { if ((error = VOP_GETATTR(vp, &va, proc->p_ucred, proc)) != 0) { return (error); } error = VOP_IOCTL(vp, DIOCGPART, (caddr_t) & dpart, FREAD, proc->p_ucred, proc); if (error) { return (error); } diskPtr->blockSize = dpart.disklab->d_secsize; diskPtr->numBlocks = DL_GETPSIZE(dpart.part) - rf_protectedSectors; diskPtr->partitionSize = DL_GETPSIZE(dpart.part); raidPtr->raid_cinfo[row][col].ci_vp = vp; raidPtr->raid_cinfo[row][col].ci_dev = va.va_rdev; /* This component was not automatically configured. */ diskPtr->auto_configured = 0; diskPtr->dev = va.va_rdev; /* * We allow the user to specify that only a fraction of the * disks should be used. This is just for debug: it speeds up * the parity scan. */ diskPtr->numBlocks = diskPtr->numBlocks * rf_sizePercentage / 100; } return (0); }
int main(int argc, char *argv[]) { int ch; struct partition *pp; struct disklabel *lp; struct disklabel mfsfakelabel; struct partition oldpartition; struct stat st; struct statfs *mp; struct rlimit rl; int fsi = -1, oflagset = 0, fso, len, n, maxpartitions; char *cp = NULL, *s1, *s2, *special, *opstring, *realdev; #ifdef MFS char mountfromname[BUFSIZ]; char *pop = NULL, node[PATH_MAX]; pid_t pid, res; struct statfs sf; struct stat mountpoint; int status; #endif uid_t mfsuid = 0; gid_t mfsgid = 0; mode_t mfsmode = 0; char *fstype = NULL; char **saveargv = argv; int ffsflag = 1; const char *errstr; long long fssize_input = 0; int fssize_usebytes = 0; u_int64_t nsecs; if (strstr(__progname, "mfs")) mfs = Nflag = quiet = 1; getphysmem(); maxpartitions = getmaxpartitions(); if (maxpartitions > 26) fatal("insane maxpartitions value %d", maxpartitions); opstring = mfs ? "P:T:b:c:e:f:i:m:o:s:" : "NO:S:T:b:c:e:f:g:h:i:m:o:qs:t:"; while ((ch = getopt(argc, argv, opstring)) != -1) { switch (ch) { case 'N': Nflag = 1; break; case 'O': Oflag = strtonum(optarg, 0, 2, &errstr); if (errstr) fatal("%s: invalid ffs version", optarg); oflagset = 1; break; case 'S': if (scan_scaled(optarg, §orsize) == -1 || sectorsize <= 0 || (sectorsize % DEV_BSIZE)) fatal("sector size invalid: %s", optarg); break; case 'T': disktype = optarg; break; case 'b': bsize = strtonum(optarg, MINBSIZE, MAXBSIZE, &errstr); if (errstr) fatal("block size is %s: %s", errstr, optarg); break; case 'c': maxfrgspercg = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("fragments per cylinder group is %s: %s", errstr, optarg); break; case 'e': maxbpg = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("blocks per file in a cylinder group is" " %s: %s", errstr, optarg); break; case 'f': fsize = strtonum(optarg, MINBSIZE / MAXFRAG, MAXBSIZE, &errstr); if (errstr) fatal("fragment size is %s: %s", errstr, optarg); break; case 'g': avgfilesize = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("average file size is %s: %s", errstr, optarg); break; case 'h': avgfilesperdir = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("average files per dir is %s: %s", errstr, optarg); break; case 'i': density = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("bytes per inode is %s: %s", errstr, optarg); break; case 'm': minfree = strtonum(optarg, 0, 99, &errstr); if (errstr) fatal("free space %% is %s: %s", errstr, optarg); break; case 'o': if (mfs) getmntopts(optarg, mopts, &mntflags); else { if (strcmp(optarg, "space") == 0) reqopt = opt = FS_OPTSPACE; else if (strcmp(optarg, "time") == 0) reqopt = opt = FS_OPTTIME; else fatal("%s: unknown optimization " "preference: use `space' or `time'.", optarg); } break; case 'q': quiet = 1; break; case 's': if (scan_scaled(optarg, &fssize_input) == -1 || fssize_input <= 0) fatal("file system size invalid: %s", optarg); fssize_usebytes = 0; /* in case of multiple -s */ for (s1 = optarg; *s1 != '\0'; s1++) if (isalpha((unsigned char)*s1)) { fssize_usebytes = 1; break; } break; case 't': fstype = optarg; if (strcmp(fstype, "ffs")) ffsflag = 0; break; #ifdef MFS case 'P': pop = optarg; break; #endif case '?': default: usage(); } if (!ffsflag) break; } argc -= optind; argv += optind; if (ffsflag && argc - mfs != 1) usage(); if (mfs) { /* Increase our data size to the max */ if (getrlimit(RLIMIT_DATA, &rl) == 0) { rl.rlim_cur = rl.rlim_max; (void)setrlimit(RLIMIT_DATA, &rl); } } special = argv[0]; if (!mfs) { char execname[PATH_MAX], name[PATH_MAX]; if (fstype == NULL) fstype = readlabelfs(special, 0); if (fstype != NULL && strcmp(fstype, "ffs")) { snprintf(name, sizeof name, "newfs_%s", fstype); saveargv[0] = name; snprintf(execname, sizeof execname, "%s/newfs_%s", _PATH_SBIN, fstype); (void)execv(execname, saveargv); snprintf(execname, sizeof execname, "%s/newfs_%s", _PATH_USRSBIN, fstype); (void)execv(execname, saveargv); err(1, "%s not found", name); } } if (mfs && !strcmp(special, "swap")) { /* * it's an MFS, mounted on "swap." fake up a label. * XXX XXX XXX */ fso = -1; /* XXX; normally done below. */ memset(&mfsfakelabel, 0, sizeof(mfsfakelabel)); mfsfakelabel.d_secsize = 512; mfsfakelabel.d_nsectors = 64; mfsfakelabel.d_ntracks = 16; mfsfakelabel.d_ncylinders = 16; mfsfakelabel.d_secpercyl = 1024; DL_SETDSIZE(&mfsfakelabel, 16384); mfsfakelabel.d_npartitions = 1; mfsfakelabel.d_version = 1; DL_SETPSIZE(&mfsfakelabel.d_partitions[0], 16384); mfsfakelabel.d_partitions[0].p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(1024, 8); mfsfakelabel.d_partitions[0].p_cpg = 16; lp = &mfsfakelabel; pp = &mfsfakelabel.d_partitions[0]; goto havelabel; } if (Nflag) { fso = -1; } else { fso = opendev(special, O_WRONLY, 0, &realdev); if (fso < 0) fatal("%s: %s", special, strerror(errno)); special = realdev; /* Bail if target special is mounted */ n = getmntinfo(&mp, MNT_NOWAIT); if (n == 0) fatal("%s: getmntinfo: %s", special, strerror(errno)); len = sizeof(_PATH_DEV) - 1; s1 = special; if (strncmp(_PATH_DEV, s1, len) == 0) s1 += len; while (--n >= 0) { s2 = mp->f_mntfromname; if (strncmp(_PATH_DEV, s2, len) == 0) { s2 += len - 1; *s2 = 'r'; } if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) fatal("%s is mounted on %s", special, mp->f_mntonname); ++mp; } } if (mfs && disktype != NULL) { lp = (struct disklabel *)getdiskbyname(disktype); if (lp == NULL) fatal("%s: unknown disk type", disktype); pp = &lp->d_partitions[1]; } else { fsi = opendev(special, O_RDONLY, 0, NULL); if (fsi < 0) fatal("%s: %s", special, strerror(errno)); if (fstat(fsi, &st) < 0) fatal("%s: %s", special, strerror(errno)); if (!mfs) { if (S_ISBLK(st.st_mode)) fatal("%s: block device", special); if (!S_ISCHR(st.st_mode)) warnx("%s: not a character-special device", special); } if (*argv[0] == '\0') fatal("empty partition name supplied"); cp = argv[0] + strlen(argv[0]) - 1; if ((*cp < 'a' || *cp > ('a' + maxpartitions - 1)) && !isdigit((unsigned char)*cp)) fatal("%s: can't figure out file system partition", argv[0]); lp = getdisklabel(special, fsi); if (!mfs) { if (pledge("stdio disklabel tty", NULL) == -1) err(1, "pledge"); } if (isdigit((unsigned char)*cp)) pp = &lp->d_partitions[0]; else pp = &lp->d_partitions[*cp - 'a']; if (DL_GETPSIZE(pp) == 0) fatal("%s: `%c' partition is unavailable", argv[0], *cp); if (pp->p_fstype == FS_BOOT) fatal("%s: `%c' partition overlaps boot program", argv[0], *cp); } havelabel: if (sectorsize == 0) { sectorsize = lp->d_secsize; if (sectorsize <= 0) fatal("%s: no default sector size", argv[0]); } if (fssize_usebytes) { nsecs = fssize_input / sectorsize; if (fssize_input % sectorsize != 0) nsecs++; } else if (fssize_input == 0) nsecs = DL_GETPSIZE(pp); else nsecs = fssize_input; if (nsecs > DL_GETPSIZE(pp) && !mfs) fatal("%s: maximum file system size on the `%c' partition is " "%llu sectors", argv[0], *cp, DL_GETPSIZE(pp)); /* Can't use DL_SECTOBLK() because sectorsize may not be from label! */ fssize = nsecs * (sectorsize / DEV_BSIZE); if (oflagset == 0 && fssize >= INT_MAX) Oflag = 2; /* FFS2 */ if (fsize == 0) { fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); if (fsize <= 0) fsize = MAXIMUM(DFL_FRAGSIZE, lp->d_secsize); } if (bsize == 0) { bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock); if (bsize <= 0) bsize = MINIMUM(DFL_BLKSIZE, 8 * fsize); } if (density == 0) density = NFPI * fsize; if (minfree < MINFREE && opt != FS_OPTSPACE && reqopt == -1) { warnx("warning: changing optimization to space " "because minfree is less than %d%%\n", MINFREE); opt = FS_OPTSPACE; } if (maxbpg == 0) { if (Oflag <= 1) maxbpg = MAXBLKPG_FFS1(bsize); else maxbpg = MAXBLKPG_FFS2(bsize); } oldpartition = *pp; #ifdef MFS if (mfs) { if (realpath(argv[1], node) == NULL) err(1, "realpath %s", argv[1]); if (stat(node, &mountpoint) < 0) err(ECANCELED, "stat %s", node); mfsuid = mountpoint.st_uid; mfsgid = mountpoint.st_gid; mfsmode = mountpoint.st_mode & ALLPERMS; } #endif mkfs(pp, special, fsi, fso, mfsmode, mfsuid, mfsgid); if (!Nflag && memcmp(pp, &oldpartition, sizeof(oldpartition))) rewritelabel(special, fso, lp); if (!Nflag) close(fso); close(fsi); #ifdef MFS if (mfs) { struct mfs_args args; memset(&args, 0, sizeof(args)); args.base = membase; args.size = fssize * DEV_BSIZE; args.export_info.ex_root = -2; if (mntflags & MNT_RDONLY) args.export_info.ex_flags = MNT_EXRDONLY; switch (pid = fork()) { case -1: err(10, "mfs"); case 0: snprintf(mountfromname, sizeof(mountfromname), "mfs:%d", getpid()); break; default: snprintf(mountfromname, sizeof(mountfromname), "mfs:%d", pid); for (;;) { /* * spin until the mount succeeds * or the child exits */ usleep(1); /* * XXX Here is a race condition: another process * can mount a filesystem which hides our * ramdisk before we see the success. */ if (statfs(node, &sf) < 0) err(ECANCELED, "statfs %s", node); if (!strcmp(sf.f_mntfromname, mountfromname) && !strncmp(sf.f_mntonname, node, MNAMELEN) && !strcmp(sf.f_fstypename, "mfs")) { if (pop != NULL) copy(pop, node, &args); exit(0); } res = waitpid(pid, &status, WNOHANG); if (res == -1) err(EDEADLK, "waitpid"); if (res != pid) continue; if (WIFEXITED(status)) { if (WEXITSTATUS(status) == 0) exit(0); errx(1, "%s: mount: %s", node, strerror(WEXITSTATUS(status))); } else errx(EDEADLK, "abnormal termination"); } /* NOTREACHED */ } (void) setsid(); (void) close(0); (void) close(1); (void) close(2); (void) chdir("/"); args.fspec = mountfromname; if (mntflags & MNT_RDONLY && pop != NULL) mntflags &= ~MNT_RDONLY; if (mount(MOUNT_MFS, node, mntflags, &args) < 0) exit(errno); /* parent prints message */ } #endif exit(0); }