/* * Find a valid disklabel. */ static char * search_label(struct of_dev *devp, u_long off, char *buf, struct disklabel *lp, u_long off0) { size_t read; struct mbr_partition *p; int i; u_long poff; struct disklabel *dlp; struct sun_disklabel *slp; int error; /* minimal requirements for archetypal disk label */ if (DL_GETDSIZE(lp) == 0) DL_SETDSIZE(lp, 0x1fffffff); lp->d_npartitions = MAXPARTITIONS; if (DL_GETPSIZE(&lp->d_partitions[0]) == 0) DL_SETPSIZE(&lp->d_partitions[0], 0x1fffffff); DL_SETPOFFSET(&lp->d_partitions[0], 0); if (strategy(devp, F_READ, off, DEV_BSIZE, buf, &read) || read != DEV_BSIZE) return ("Cannot read label"); /* Check for a disk label. */ dlp = (struct disklabel *) (buf + LABELOFFSET); if (dlp->d_magic == DISKMAGIC) { if (dkcksum(dlp)) return ("corrupt disk label"); *lp = *dlp; DNPRINTF(BOOT_D_OFDEV, "search_label: found disk label\n"); return (NULL); } /* Check for a Sun disk label (for PROM compatibility). */ slp = (struct sun_disklabel *)buf; if (slp->sl_magic == SUN_DKMAGIC) { if (disklabel_sun_to_bsd(slp, lp) != 0) return ("corrupt disk label"); DNPRINTF(BOOT_D_OFDEV, "search_label: found disk label\n"); return (NULL); } return ("no disk label"); }
/* * Read an ascii label in from FILE f, * in the same format as that put out by display(), * and fill in lp. */ int getasciilabel(FILE *f, struct disklabel *lp) { char **cpp, *cp; const char *errstr; struct partition *pp; char *tp, *s, line[BUFSIZ]; int lineno = 0, errors = 0; u_int32_t v, fsize; u_int64_t lv; lp->d_version = 1; lp->d_bbsize = BBSIZE; /* XXX */ lp->d_sbsize = SBSIZE; /* XXX */ while (fgets(line, sizeof(line), f)) { lineno++; if ((cp = strpbrk(line, "#\r\n"))) *cp = '\0'; cp = skip(line); if (cp == NULL) continue; tp = strchr(cp, ':'); if (tp == NULL) { warnx("line %d: syntax error", lineno); errors++; continue; } *tp++ = '\0', tp = skip(tp); if (!strcmp(cp, "type")) { if (tp == NULL) tp = "unknown"; else if (strcasecmp(tp, "IDE") == 0) tp = "ESDI"; cpp = dktypenames; for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) if ((s = *cpp) && !strcasecmp(s, tp)) { lp->d_type = cpp - dktypenames; goto next; } v = GETNUM(lp->d_type, tp, 0, &errstr); if (errstr || v >= DKMAXTYPES) warnx("line %d: warning, unknown disk type: %s", lineno, tp); lp->d_type = v; continue; } if (!strcmp(cp, "flags")) { for (v = 0; (cp = tp) && *cp != '\0';) { tp = word(cp); if (!strcmp(cp, "badsect")) v |= D_BADSECT; else if (!strcmp(cp, "vendor")) v |= D_VENDOR; else { warnx("line %d: bad flag: %s", lineno, cp); errors++; } } lp->d_flags = v; continue; } if (!strcmp(cp, "drivedata")) { int i; for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { v = GETNUM(lp->d_drivedata[i], cp, 0, &errstr); if (errstr) warnx("line %d: bad drivedata %s", lineno, cp); lp->d_drivedata[i++] = v; tp = word(cp); } continue; } if (sscanf(cp, "%d partitions", &v) == 1) { if (v == 0 || v > MAXPARTITIONS) { warnx("line %d: bad # of partitions", lineno); lp->d_npartitions = MAXPARTITIONS; errors++; } else lp->d_npartitions = v; continue; } if (tp == NULL) tp = ""; if (!strcmp(cp, "disk")) { strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); continue; } if (!strcmp(cp, "label")) { strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); continue; } if (!strcmp(cp, "duid")) { if (duid_parse(lp, tp) != 0) { warnx("line %d: bad %s: %s", lineno, cp, tp); errors++; } continue; } if (!strcmp(cp, "bytes/sector")) { v = GETNUM(lp->d_secsize, tp, 1, &errstr); if (errstr || (v % 512) != 0) { warnx("line %d: bad %s: %s", lineno, cp, tp); errors++; } else lp->d_secsize = v; continue; } if (!strcmp(cp, "sectors/track")) { v = GETNUM(lp->d_nsectors, tp, 1, &errstr); if (errstr) { warnx("line %d: bad %s: %s", lineno, cp, tp); errors++; } else lp->d_nsectors = v; continue; } if (!strcmp(cp, "sectors/cylinder")) { v = GETNUM(lp->d_secpercyl, tp, 1, &errstr); if (errstr) { warnx("line %d: bad %s: %s", lineno, cp, tp); errors++; } else lp->d_secpercyl = v; continue; } if (!strcmp(cp, "tracks/cylinder")) { v = GETNUM(lp->d_ntracks, tp, 1, &errstr); if (errstr) { warnx("line %d: bad %s: %s", lineno, cp, tp); errors++; } else lp->d_ntracks = v; continue; } if (!strcmp(cp, "cylinders")) { v = GETNUM(lp->d_ncylinders, tp, 1, &errstr); if (errstr) { warnx("line %d: bad %s: %s", lineno, cp, tp); errors++; } else lp->d_ncylinders = v; continue; } if (!strcmp(cp, "total sectors")) { lv = GETNUM(lv, tp, 1, &errstr); if (errstr) { warnx("line %d: bad %s: %s", lineno, cp, tp); errors++; } else { DL_SETDSIZE(lp, lv); } continue; } /* Ignore fields that are no longer in the disklabel. */ if (!strcmp(cp, "rpm") || !strcmp(cp, "interleave") || !strcmp(cp, "trackskew") || !strcmp(cp, "cylinderskew") || !strcmp(cp, "headswitch") || !strcmp(cp, "track-to-track seek")) continue; /* Ignore fields that are forcibly set when label is read. */ if (!strcmp(cp, "total sectors") || !strcmp(cp, "boundstart") || !strcmp(cp, "boundend")) continue; if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { unsigned int part = *cp - 'a'; if (part >= lp->d_npartitions) { if (part >= MAXPARTITIONS) { warnx("line %d: bad partition name: %s", lineno, cp); errors++; continue; } else { lp->d_npartitions = part + 1; } } pp = &lp->d_partitions[part]; #define NXTNUM(n, field, errstr) { \ if (tp == NULL) { \ warnx("line %d: too few fields", lineno); \ errors++; \ break; \ } else \ cp = tp, tp = word(cp), (n) = GETNUM(field, cp, 0, errstr); \ } NXTNUM(lv, lv, &errstr); if (errstr) { warnx("line %d: bad partition size: %s", lineno, cp); errors++; } else { DL_SETPSIZE(pp, lv); } NXTNUM(lv, lv, &errstr); if (errstr) { warnx("line %d: bad partition offset: %s", lineno, cp); errors++; } else { DL_SETPOFFSET(pp, lv); } if (tp == NULL) { pp->p_fstype = FS_UNUSED; goto gottype; } cp = tp, tp = word(cp); cpp = fstypenames; for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) if ((s = *cpp) && !strcasecmp(s, cp)) { pp->p_fstype = cpp - fstypenames; goto gottype; } if (isdigit((unsigned char)*cp)) v = GETNUM(pp->p_fstype, cp, 0, &errstr); else v = FSMAXTYPES; if (errstr || v >= FSMAXTYPES) { warnx("line %d: warning, unknown filesystem type: %s", lineno, cp); v = FS_UNUSED; } pp->p_fstype = v; gottype: switch (pp->p_fstype) { case FS_UNUSED: /* XXX */ if (tp == NULL) /* ok to skip fsize/bsize */ break; NXTNUM(fsize, fsize, &errstr); if (fsize == 0) break; NXTNUM(v, v, &errstr); pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, v / fsize); break; case FS_BSDFFS: NXTNUM(fsize, fsize, &errstr); if (fsize == 0) break; NXTNUM(v, v, &errstr); pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, v / fsize); NXTNUM(pp->p_cpg, pp->p_cpg, &errstr); break; default: break; } continue; } warnx("line %d: unknown field: %s", lineno, cp); errors++; next: ; } errors += checklabel(lp); return (errors > 0); }
int readdpmelabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp, daddr_t *partoffp, int spoofonly) { int i, part_cnt, n, hfspartoff = -1; long long hfspartend = DL_GETDSIZE(lp); struct part_map_entry *part; /* First check for a DPME (HFS) disklabel */ bp->b_blkno = 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)) return (bp->b_error); /* if successful, wander through DPME partition table */ part = (struct part_map_entry *)bp->b_data; /* if first partition is not valid, assume not HFS/DPME partitioned */ if (part->pmSig != PART_ENTRY_MAGIC) return (EINVAL); /* not a DPME partition */ part_cnt = part->pmMapBlkCnt; n = 8; for (i = 0; i < part_cnt; i++) { struct partition *pp; char *s; bp->b_blkno = LABELSECTOR + i; 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); part = (struct part_map_entry *)bp->b_data; /* toupper the string, in case caps are different... */ for (s = part->pmPartType; *s; s++) if ((*s >= 'a') && (*s <= 'z')) *s = (*s - 'a' + 'A'); if (strcmp(part->pmPartType, PART_TYPE_OPENBSD) == 0) { hfspartoff = part->pmPyPartStart; hfspartend = hfspartoff + part->pmPartBlkCnt; if (partoffp) { *partoffp = hfspartoff; return (0); } else { DL_SETBSTART(lp, hfspartoff); DL_SETBEND(lp, hfspartend < DL_GETDSIZE(lp) ? hfspartend : DL_GETDSIZE(lp)); } continue; } if (n >= MAXPARTITIONS || partoffp) continue; /* Currently we spoof HFS partitions only. */ if (strcmp(part->pmPartType, PART_TYPE_MAC) == 0) { pp = &lp->d_partitions[n]; DL_SETPOFFSET(pp, part->pmPyPartStart); DL_SETPSIZE(pp, part->pmPartBlkCnt); pp->p_fstype = FS_HFS; n++; } } if (hfspartoff == -1) return (EINVAL); /* no OpenBSD partition inside DPME label */ if (spoofonly) return (0); /* next, dig out disk label */ bp->b_blkno = hfspartoff; 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); /* * Do OpenBSD disklabel validation/adjustment. * * N.B: No matter what the bits are on the disk, we now have the * disklabel for this dpme disk. DO NOT proceed to readdoslabel(), * iso_spooflabel(), * etc. */ checkdisklabel(bp->b_data + LABELOFFSET, lp, hfspartoff, hfspartend); return (0); }
/* * Do a lazy probe on the underlying media to check if it's a UDF volume, in * which case we fake a disk label for it. */ int udf_disklabelspoof(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp) { char vid[32]; int i, bsize = 2048, error = EINVAL; uint32_t sector = 256, mvds_start, mvds_end; struct buf *bp; struct anchor_vdp avdp; struct pri_vol_desc *pvd; /* * Get a buffer to work with. */ bp = geteblk(bsize); bp->b_dev = dev; /* * Look for an Anchor Volume Descriptor at sector 256. */ bp->b_blkno = sector * btodb(bsize); bp->b_bcount = bsize; CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); SET(bp->b_flags, B_BUSY | B_READ | B_RAW); bp->b_resid = bp->b_blkno / lp->d_secpercyl; (*strat)(bp); if (biowait(bp)) goto out; if (udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)) goto out; bcopy(bp->b_data, &avdp, sizeof(avdp)); mvds_start = letoh32(avdp.main_vds_ex.loc); mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize; /* * Then try to find a reference to a Primary Volume Descriptor. */ for (sector = mvds_start; sector < mvds_end; sector++) { bp->b_blkno = sector * btodb(bsize); bp->b_bcount = bsize; CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); SET(bp->b_flags, B_BUSY | B_READ | B_RAW); bp->b_resid = bp->b_blkno / lp->d_secpercyl; (*strat)(bp); if (biowait(bp)) goto out; pvd = (struct pri_vol_desc *)bp->b_data; if (!udf_checktag(&pvd->tag, TAGID_PRI_VOL)) break; } /* * If we couldn't find a reference, bail out. */ if (sector == mvds_end) goto out; /* * Okay, it's a UDF volume. Spoof a disk label for it. */ if (udf_transname(pvd->vol_id, vid, sizeof(pvd->vol_id) - 1, NULL)) strlcpy(lp->d_typename, vid, sizeof(lp->d_typename)); for (i = 0; i < MAXPARTITIONS; i++) { DL_SETPSIZE(&lp->d_partitions[i], 0); DL_SETPOFFSET(&lp->d_partitions[i], 0); } /* * Fake two partitions, 'a' and 'c'. */ DL_SETPSIZE(&lp->d_partitions[0], DL_GETDSIZE(lp)); lp->d_partitions[0].p_fstype = FS_UDF; DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); lp->d_partitions[RAW_PART].p_fstype = FS_UDF; lp->d_npartitions = MAXPARTITIONS; lp->d_version = 1; lp->d_bbsize = 8192; /* Fake. */ lp->d_sbsize = 64*1024; /* Fake. */ lp->d_magic = DISKMAGIC; lp->d_magic2 = DISKMAGIC; lp->d_checksum = dkcksum(lp); error = 0; out: bp->b_flags |= B_INVAL; brelse(bp); return (error); }
/* * 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))); }
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); }
/* * 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 disklabel * getdiskbyname(const char *name) { static struct disklabel disk; struct disklabel *dp = &disk; struct partition *pp; char *buf; char *db_array[2] = { _PATH_DISKTAB, 0 }; char *cp, *cq; char p, max, psize[3], pbsize[3], pfsize[3], poffset[3], ptype[3]; u_int32_t *dx; if (cgetent(&buf, db_array, (char *) name) < 0) return NULL; bzero((char *)&disk, sizeof(disk)); /* * typename */ cq = dp->d_typename; cp = buf; while (cq < dp->d_typename + sizeof(dp->d_typename) - 1 && (*cq = *cp) && *cq != '|' && *cq != ':') cq++, cp++; *cq = '\0'; if (cgetcap(buf, "sf", ':') != NULL) dp->d_flags |= D_BADSECT; #define getnumdflt(field, dname, dflt) \ { long f; (field) = (cgetnum(buf, dname, &f) == -1) ? (dflt) : f; } #define getnum(field, dname) \ { long f; cgetnum(buf, dname, &f); field = f; } getnumdflt(dp->d_secsize, "se", DEV_BSIZE); getnum(dp->d_ntracks, "nt"); getnum(dp->d_nsectors, "ns"); getnum(dp->d_ncylinders, "nc"); if (cgetstr(buf, "dt", &cq) > 0) dp->d_type = (u_short)gettype(cq, dktypenames); else getnumdflt(dp->d_type, "dt", 0); getnumdflt(dp->d_secpercyl, "sc", dp->d_nsectors * dp->d_ntracks); /* XXX */ dp->d_secperunith = 0; getnumdflt(dp->d_secperunit, "su", dp->d_secpercyl * dp->d_ncylinders); getnumdflt(dp->d_bbsize, "bs", BBSIZE); getnumdflt(dp->d_sbsize, "sb", SBSIZE); strlcpy(psize, "px", sizeof psize); strlcpy(pbsize, "bx", sizeof pbsize); strlcpy(pfsize, "fx", sizeof pfsize); strlcpy(poffset, "ox", sizeof poffset); strlcpy(ptype, "tx", sizeof ptype); max = 'a' - 1; pp = &dp->d_partitions[0]; dp->d_version = 1; for (p = 'a'; p < 'a' + MAXPARTITIONS; p++, pp++) { long f; psize[1] = pbsize[1] = pfsize[1] = poffset[1] = ptype[1] = p; /* XXX */ if (cgetnum(buf, psize, &f) == -1) DL_SETPSIZE(pp, 0); else { u_int32_t fsize, frag = 8; DL_SETPSIZE(pp, f); /* XXX */ pp->p_offseth = 0; getnum(pp->p_offset, poffset); getnumdflt(fsize, pfsize, 0); if (fsize) { long bsize; if (cgetnum(buf, pbsize, &bsize) == 0) frag = bsize / fsize; pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag); } getnumdflt(pp->p_fstype, ptype, 0); if (pp->p_fstype == 0 && cgetstr(buf, ptype, &cq) > 0) pp->p_fstype = (u_char)gettype(cq, fstypenames); max = p; } } dp->d_npartitions = max + 1 - 'a'; (void)strlcpy(psize, "dx", sizeof psize); dx = dp->d_drivedata; for (p = '0'; p < '0' + NDDATA; p++, dx++) { psize[1] = p; getnumdflt(*dx, psize, 0); } dp->d_magic = DISKMAGIC; dp->d_magic2 = DISKMAGIC; free(buf); return (dp); }
void cdprobe(void) { struct diskinfo *dip; int cddev = bios_cddev & 0xff; /* Another BIOS boot device... */ if (bios_cddev == -1) /* Not been set, so don't use */ return; dip = alloc(sizeof(struct diskinfo)); bzero(dip, sizeof(*dip)); #if 0 if (bios_getdiskinfo(cddev, &dip->bios_info)) { printf(" <!cd0>"); /* XXX */ free(dip, 0); return; } #endif printf(" cd0"); dip->bios_info.bios_number = cddev; dip->bios_info.bios_edd = 1; /* Use the LBA calls */ dip->bios_info.flags |= BDI_GOODLABEL | BDI_EL_TORITO; dip->bios_info.checksum = 0; /* just in case */ dip->bios_info.bsd_dev = MAKEBOOTDEV(6, 0, 0, 0, RAW_PART); /* Create an imaginary disk label */ dip->disklabel.d_secsize = 2048; dip->disklabel.d_ntracks = 1; dip->disklabel.d_nsectors = 100; dip->disklabel.d_ncylinders = 1; dip->disklabel.d_secpercyl = dip->disklabel.d_ntracks * dip->disklabel.d_nsectors; if (dip->disklabel.d_secpercyl == 0) { dip->disklabel.d_secpercyl = 100; /* as long as it's not 0, since readdisklabel divides by it */ } strncpy(dip->disklabel.d_typename, "ATAPI CD-ROM", sizeof(dip->disklabel.d_typename)); dip->disklabel.d_type = DTYPE_ATAPI; strncpy(dip->disklabel.d_packname, "fictitious", sizeof(dip->disklabel.d_packname)); DL_SETDSIZE(&dip->disklabel, 100); dip->disklabel.d_bbsize = 2048; dip->disklabel.d_sbsize = 2048; /* 'a' partition covering the "whole" disk */ DL_SETPOFFSET(&dip->disklabel.d_partitions[0], 0); DL_SETPSIZE(&dip->disklabel.d_partitions[0], 100); dip->disklabel.d_partitions[0].p_fstype = FS_UNUSED; /* The raw partition is special */ DL_SETPOFFSET(&dip->disklabel.d_partitions[RAW_PART], 0); DL_SETPSIZE(&dip->disklabel.d_partitions[RAW_PART], 100); dip->disklabel.d_partitions[RAW_PART].p_fstype = FS_UNUSED; dip->disklabel.d_npartitions = MAXPARTITIONS; dip->disklabel.d_magic = DISKMAGIC; dip->disklabel.d_magic2 = DISKMAGIC; dip->disklabel.d_checksum = dkcksum(&dip->disklabel); /* Add to queue of disks */ TAILQ_INSERT_TAIL(&disklist, dip, list); }
int readsgilabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp, daddr_t *partoffp, int spoofonly) { struct sgilabel *dlp; int i, *p, cs = 0; daddr_t fsoffs, fsend; int error, offset; /* if successful, locate disk label within block and validate */ error = readdisksector(bp, strat, lp, 0); if (error) return (error); fsoffs = DL_SECTOBLK(lp, DL_GETBSTART(lp)); fsend = DL_SECTOBLK(lp, DL_GETBEND(lp)); dlp = (struct sgilabel *)(bp->b_data + LABELOFFSET); if (dlp->magic != htobe32(SGILABEL_MAGIC)) goto finished; if (dlp->partitions[0].blocks == 0) return (EINVAL); fsoffs = (long long)dlp->partitions[0].first; fsend = fsoffs + dlp->partitions[0].blocks; /* Only came here to find the offset... */ if (partoffp) { *partoffp = fsoffs; goto finished; } p = (int *)dlp; i = sizeof(struct sgilabel) / sizeof(int); while (i--) cs += *p++; if (cs != 0) return (EINVAL); /* sgilabel checksum error */ /* Spoof info from sgi label, in case there is no OpenBSD label. */ lp->d_npartitions = MAXPARTITIONS; for (i = 0; i < 16; i++) { int bsd = maptab[i].m; int type = maptab[i].b; if (spoofonly && type != FS_UNUSED && type != FS_OTHER) continue; DL_SETPOFFSET(&lp->d_partitions[bsd], dlp->partitions[i].first); DL_SETPSIZE(&lp->d_partitions[bsd], dlp->partitions[i].blocks); lp->d_partitions[bsd].p_fstype = type; if (type == FS_BSDFFS) { lp->d_partitions[bsd].p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(1024, 8); lp->d_partitions[bsd].p_cpg = 16; } } DL_SETBSTART(lp, DL_BLKTOSEC(lp, fsoffs)); DL_SETBEND(lp, DL_BLKTOSEC(lp, fsend)); lp->d_version = 1; lp->d_flags = D_VENDOR; lp->d_checksum = 0; lp->d_checksum = dkcksum(lp); finished: /* record the OpenBSD partition's placement for the caller */ if (partoffp) *partoffp = fsoffs; else { DL_SETBSTART(lp, DL_BLKTOSEC(lp, fsoffs)); DL_SETBEND(lp, DL_BLKTOSEC(lp, fsend)); } /* don't read the on-disk label if we are in spoofed-only mode */ if (spoofonly) return (0); error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, fsoffs + LABELSECTOR)); if (error) return (error); offset = DL_BLKOFFSET(lp, fsoffs + LABELSECTOR) + LABELOFFSET; /* * Do OpenBSD disklabel validation/adjustment. * * N.B: No matter what the bits are on the disk, we now have the * OpenBSD disklabel for this sgi disk. DO NOT proceed to * readdoslabel(), iso_spooflabel(), etc. */ checkdisklabel(bp->b_data + offset, lp, fsoffs, fsend); return (0); }
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); }