Index: head/sbin/fsck_ffs/setup.c =================================================================== --- head/sbin/fsck_ffs/setup.c (revision 276736) +++ head/sbin/fsck_ffs/setup.c (revision 276737) @@ -1,536 +1,449 @@ /* * Copyright (c) 1980, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static const char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #define FSTYPENAMES #include #include #include #include #include #include #include #include #include #include #include #include "fsck.h" struct bufarea asblk; #define altsblock (*asblk.b_un.b_fs) #define POWEROF2(num) (((num) & ((num) - 1)) == 0) static void badsb(int listerr, const char *s); -static int calcsb(char *dev, int devfd, struct fs *fs); -static struct disklabel *getdisklabel(char *s, int fd); /* * Read in a superblock finding an alternate if necessary. * Return 1 if successful, 0 if unsuccessful, -1 if file system * is already clean (ckclean and preen mode only). */ int setup(char *dev) { long cg, asked, i, j; long bmapsize; struct stat statb; struct fs proto; size_t size; havesb = 0; fswritefd = -1; cursnapshot = 0; if (stat(dev, &statb) < 0) { printf("Can't stat %s: %s\n", dev, strerror(errno)); if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } return (0); } if ((statb.st_mode & S_IFMT) != S_IFCHR && (statb.st_mode & S_IFMT) != S_IFBLK) { if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { unlink(snapname); printf("background fsck lacks a snapshot\n"); exit(EEXIT); } if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) { cursnapshot = statb.st_ino; } else { if (cvtlevel == 0 || (statb.st_flags & SF_SNAPSHOT) == 0) { if (preen && bkgrdflag) { unlink(snapname); bkgrdflag = 0; } pfatal("%s is not a disk device", dev); if (reply("CONTINUE") == 0) { if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } return (0); } } else { if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } pfatal("cannot convert a snapshot"); exit(EEXIT); } } } if ((fsreadfd = open(dev, O_RDONLY)) < 0) { if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } printf("Can't open %s: %s\n", dev, strerror(errno)); return (0); } if (bkgrdflag) { unlink(snapname); size = MIBSIZE; if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0|| sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0|| sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0|| sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 || sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) { pfatal("kernel lacks background fsck support\n"); exit(EEXIT); } /* * When kernel is lack of runtime bgfsck superblock summary * adjustment functionality, it does not mean we can not * continue, as old kernels will recompute the summary at * mount time. However, it will be an unexpected softupdates * inconsistency if it turns out that the summary is still * incorrect. Set a flag so subsequent operation can know * this. */ bkgrdsumadj = 1; if (sysctlnametomib("vfs.ffs.adjndir", adjndir, &size) < 0 || sysctlnametomib("vfs.ffs.adjnbfree", adjnbfree, &size) < 0 || sysctlnametomib("vfs.ffs.adjnifree", adjnifree, &size) < 0 || sysctlnametomib("vfs.ffs.adjnffree", adjnffree, &size) < 0 || sysctlnametomib("vfs.ffs.adjnumclusters", adjnumclusters, &size) < 0) { bkgrdsumadj = 0; pwarn("kernel lacks runtime superblock summary adjustment support"); } cmd.version = FFS_CMD_VERSION; cmd.handle = fsreadfd; fswritefd = -1; } if (preen == 0) printf("** %s", dev); if (bkgrdflag == 0 && (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) { fswritefd = -1; if (preen) pfatal("NO WRITE ACCESS"); printf(" (NO WRITE)"); } if (preen == 0) printf("\n"); /* * Read in the superblock, looking for alternates if necessary */ if (readsb(1) == 0) { skipclean = 0; - if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) + if (bflag || preen) return(0); if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) return (0); for (cg = 0; cg < proto.fs_ncg; cg++) { bflag = fsbtodb(&proto, cgsblock(&proto, cg)); if (readsb(0) != 0) break; } if (cg >= proto.fs_ncg) { printf("%s %s\n%s %s\n%s %s\n", "SEARCH FOR ALTERNATE SUPER-BLOCK", "FAILED. YOU MUST USE THE", "-b OPTION TO FSCK TO SPECIFY THE", "LOCATION OF AN ALTERNATE", "SUPER-BLOCK TO SUPPLY NEEDED", "INFORMATION; SEE fsck_ffs(8)."); bflag = 0; return(0); } pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); bflag = 0; } if (skipclean && ckclean && sblock.fs_clean) { pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); return (-1); } maxfsblock = sblock.fs_size; maxino = sblock.fs_ncg * sblock.fs_ipg; /* * Check and potentially fix certain fields in the super block. */ if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); if (reply("SET TO DEFAULT") == 1) { sblock.fs_optim = FS_OPTTIME; sbdirty(); } } if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", sblock.fs_minfree); if (reply("SET TO DEFAULT") == 1) { sblock.fs_minfree = 10; sbdirty(); } } if (sblock.fs_magic == FS_UFS1_MAGIC && sblock.fs_old_inodefmt < FS_44INODEFMT) { pwarn("Format of file system is too old.\n"); pwarn("Must update to modern format using a version of fsck\n"); pfatal("from before 2002 with the command ``fsck -c 2''\n"); exit(EEXIT); } if (asblk.b_dirty && !bflag) { memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); flush(fswritefd, &asblk); } /* * read in the summary info. */ asked = 0; sblock.fs_csp = Calloc(1, sblock.fs_cssize); if (sblock.fs_csp == NULL) { printf("cannot alloc %u bytes for cg summary info\n", (unsigned)sblock.fs_cssize); goto badsb; } for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { size = sblock.fs_cssize - i < sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize; readcnt[sblk.b_type]++; if (blread(fsreadfd, (char *)sblock.fs_csp + i, fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), size) != 0 && !asked) { pfatal("BAD SUMMARY INFORMATION"); if (reply("CONTINUE") == 0) { ckfini(0); exit(EEXIT); } asked++; } } /* * allocate and initialize the necessary maps */ bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short)); blockmap = Calloc((unsigned)bmapsize, sizeof (char)); if (blockmap == NULL) { printf("cannot alloc %u bytes for blockmap\n", (unsigned)bmapsize); goto badsb; } inostathead = Calloc((unsigned)(sblock.fs_ncg), sizeof(struct inostatlist)); if (inostathead == NULL) { printf("cannot alloc %u bytes for inostathead\n", (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg))); goto badsb; } numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128); dirhash = numdirs; inplast = 0; listmax = numdirs + 10; inpsort = (struct inoinfo **)Calloc((unsigned)listmax, sizeof(struct inoinfo *)); inphead = (struct inoinfo **)Calloc((unsigned)numdirs, sizeof(struct inoinfo *)); if (inpsort == NULL || inphead == NULL) { printf("cannot alloc %ju bytes for inphead\n", (uintmax_t)numdirs * sizeof(struct inoinfo *)); goto badsb; } bufinit(); if (sblock.fs_flags & FS_DOSOFTDEP) usedsoftdep = 1; else usedsoftdep = 0; return (1); badsb: ckfini(0); return (0); } /* * Possible superblock locations ordered from most to least likely. */ static int sblock_try[] = SBLOCKSEARCH; #define BAD_MAGIC_MSG \ "The previous newfs operation on this volume did not complete.\n" \ "You must complete newfs before mounting this volume.\n" /* * Read in the super block and its summary info. */ int readsb(int listerr) { ufs2_daddr_t super; int i; if (bflag) { super = bflag; readcnt[sblk.b_type]++; if ((blread(fsreadfd, (char *)&sblock, super, (long)SBLOCKSIZE))) return (0); if (sblock.fs_magic == FS_BAD_MAGIC) { fprintf(stderr, BAD_MAGIC_MSG); exit(11); } if (sblock.fs_magic != FS_UFS1_MAGIC && sblock.fs_magic != FS_UFS2_MAGIC) { fprintf(stderr, "%d is not a file system superblock\n", bflag); return (0); } } else { for (i = 0; sblock_try[i] != -1; i++) { super = sblock_try[i] / dev_bsize; readcnt[sblk.b_type]++; if ((blread(fsreadfd, (char *)&sblock, super, (long)SBLOCKSIZE))) return (0); if (sblock.fs_magic == FS_BAD_MAGIC) { fprintf(stderr, BAD_MAGIC_MSG); exit(11); } if ((sblock.fs_magic == FS_UFS1_MAGIC || (sblock.fs_magic == FS_UFS2_MAGIC && sblock.fs_sblockloc == sblock_try[i])) && sblock.fs_ncg >= 1 && sblock.fs_bsize >= MINBSIZE && sblock.fs_sbsize >= roundup(sizeof(struct fs), dev_bsize)) break; } if (sblock_try[i] == -1) { fprintf(stderr, "Cannot find file system superblock\n"); return (0); } } /* * Compute block size that the file system is based on, * according to fsbtodb, and adjust superblock block number * so we can tell if this is an alternate later. */ super *= dev_bsize; dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); sblk.b_bno = super / dev_bsize; sblk.b_size = SBLOCKSIZE; if (bflag) goto out; /* * Compare all fields that should not differ in alternate super block. * When an alternate super-block is specified this check is skipped. */ getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize); if (asblk.b_errs) return (0); if (altsblock.fs_sblkno != sblock.fs_sblkno || altsblock.fs_cblkno != sblock.fs_cblkno || altsblock.fs_iblkno != sblock.fs_iblkno || altsblock.fs_dblkno != sblock.fs_dblkno || altsblock.fs_ncg != sblock.fs_ncg || altsblock.fs_bsize != sblock.fs_bsize || altsblock.fs_fsize != sblock.fs_fsize || altsblock.fs_frag != sblock.fs_frag || altsblock.fs_bmask != sblock.fs_bmask || altsblock.fs_fmask != sblock.fs_fmask || altsblock.fs_bshift != sblock.fs_bshift || altsblock.fs_fshift != sblock.fs_fshift || altsblock.fs_fragshift != sblock.fs_fragshift || altsblock.fs_fsbtodb != sblock.fs_fsbtodb || altsblock.fs_sbsize != sblock.fs_sbsize || altsblock.fs_nindir != sblock.fs_nindir || altsblock.fs_inopb != sblock.fs_inopb || altsblock.fs_cssize != sblock.fs_cssize || altsblock.fs_ipg != sblock.fs_ipg || altsblock.fs_fpg != sblock.fs_fpg || altsblock.fs_magic != sblock.fs_magic) { badsb(listerr, "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); return (0); } out: /* * If not yet done, update UFS1 superblock with new wider fields. */ if (sblock.fs_magic == FS_UFS1_MAGIC && sblock.fs_maxbsize != sblock.fs_bsize) { sblock.fs_maxbsize = sblock.fs_bsize; sblock.fs_time = sblock.fs_old_time; sblock.fs_size = sblock.fs_old_size; sblock.fs_dsize = sblock.fs_old_dsize; sblock.fs_csaddr = sblock.fs_old_csaddr; sblock.fs_cstotal.cs_ndir = sblock.fs_old_cstotal.cs_ndir; sblock.fs_cstotal.cs_nbfree = sblock.fs_old_cstotal.cs_nbfree; sblock.fs_cstotal.cs_nifree = sblock.fs_old_cstotal.cs_nifree; sblock.fs_cstotal.cs_nffree = sblock.fs_old_cstotal.cs_nffree; } havesb = 1; return (1); } static void badsb(int listerr, const char *s) { if (!listerr) return; if (preen) printf("%s: ", cdevname); pfatal("BAD SUPER BLOCK: %s\n", s); } void sblock_init(void) { - struct disklabel *lp; fswritefd = -1; fsmodified = 0; lfdir = 0; initbarea(&sblk, BT_SUPERBLK); initbarea(&asblk, BT_SUPERBLK); sblk.b_un.b_buf = Malloc(SBLOCKSIZE); asblk.b_un.b_buf = Malloc(SBLOCKSIZE); if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) errx(EEXIT, "cannot allocate space for superblock"); - if ((lp = getdisklabel(NULL, fsreadfd))) - real_dev_bsize = dev_bsize = secsize = lp->d_secsize; - else - dev_bsize = secsize = DEV_BSIZE; -} - -/* - * Calculate a prototype superblock based on information in the disk label. - * When done the cgsblock macro can be calculated and the fs_ncg field - * can be used. Do NOT attempt to use other macros without verifying that - * their needed information is available! - */ -static int -calcsb(char *dev, int devfd, struct fs *fs) -{ - struct disklabel *lp; - struct partition *pp; - char *cp; - int i, nspf; - - cp = strchr(dev, '\0') - 1; - if (cp == (char *)-1 || ((*cp < 'a' || *cp > 'h') && !isdigit(*cp))) { - pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); - return (0); - } - lp = getdisklabel(dev, devfd); - if (isdigit(*cp)) - pp = &lp->d_partitions[0]; - else - pp = &lp->d_partitions[*cp - 'a']; - if (pp->p_fstype != FS_BSDFFS) { - pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n", - dev, pp->p_fstype < FSMAXTYPES ? - fstypenames[pp->p_fstype] : "unknown"); - return (0); - } - if (pp->p_fsize == 0 || pp->p_frag == 0 || - pp->p_cpg == 0 || pp->p_size == 0) { - pfatal("%s: %s: type %s fsize %d, frag %d, cpg %d, size %d\n", - dev, "INCOMPLETE LABEL", fstypenames[pp->p_fstype], - pp->p_fsize, pp->p_frag, pp->p_cpg, pp->p_size); - return (0); - } - memset(fs, 0, sizeof(struct fs)); - fs->fs_fsize = pp->p_fsize; - fs->fs_frag = pp->p_frag; - fs->fs_size = pp->p_size; - fs->fs_sblkno = roundup( - howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize), - fs->fs_frag); - nspf = fs->fs_fsize / lp->d_secsize; - for (fs->fs_fsbtodb = 0, i = nspf; i > 1; i >>= 1) - fs->fs_fsbtodb++; - dev_bsize = lp->d_secsize; - if (fs->fs_magic == FS_UFS2_MAGIC) { - fs->fs_fpg = pp->p_cpg; - fs->fs_ncg = howmany(fs->fs_size, fs->fs_fpg); - } else /* if (fs->fs_magic == FS_UFS1_MAGIC) */ { - fs->fs_old_cpg = pp->p_cpg; - fs->fs_old_cgmask = 0xffffffff; - for (i = lp->d_ntracks; i > 1; i >>= 1) - fs->fs_old_cgmask <<= 1; - if (!POWEROF2(lp->d_ntracks)) - fs->fs_old_cgmask <<= 1; - fs->fs_old_cgoffset = roundup(howmany(lp->d_nsectors, nspf), - fs->fs_frag); - fs->fs_fpg = (fs->fs_old_cpg * lp->d_secpercyl) / nspf; - fs->fs_ncg = howmany(fs->fs_size / lp->d_secpercyl, - fs->fs_old_cpg); - } - return (1); -} - -static struct disklabel * -getdisklabel(char *s, int fd) -{ - static struct disklabel lab; - - if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { - if (s == NULL) - return ((struct disklabel *)NULL); - pwarn("ioctl (GCINFO): %s\n", strerror(errno)); - errx(EEXIT, "%s: can't read disk label", s); - } - return (&lab); + dev_bsize = secsize = DEV_BSIZE; } Index: head/sbin/fsirand/fsirand.c =================================================================== --- head/sbin/fsirand/fsirand.c (revision 276736) +++ head/sbin/fsirand/fsirand.c (revision 276737) @@ -1,314 +1,303 @@ /* $OpenBSD: fsirand.c,v 1.9 1997/02/28 00:46:33 millert Exp $ */ /* * Copyright (c) 1997 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Todd C. Miller. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include -#include #include #include #include #include #include #include #include #include #include #include #include #include static void usage(void) __dead2; int fsirand(char *); /* * Possible superblock locations ordered from most to least likely. */ static int sblock_try[] = SBLOCKSEARCH; static int printonly = 0, force = 0, ignorelabel = 0; int main(int argc, char *argv[]) { int n, ex = 0; struct rlimit rl; while ((n = getopt(argc, argv, "bfp")) != -1) { switch (n) { case 'b': ignorelabel++; break; case 'p': printonly++; break; case 'f': force++; break; default: usage(); } } if (argc - optind < 1) usage(); srandomdev(); /* Increase our data size to the max */ if (getrlimit(RLIMIT_DATA, &rl) == 0) { rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_DATA, &rl) < 0) warn("can't get resource limit to max data size"); } else warn("can't get resource limit for data size"); for (n = optind; n < argc; n++) { if (argc - optind != 1) (void)puts(argv[n]); ex += fsirand(argv[n]); if (n < argc - 1) putchar('\n'); } exit(ex); } int fsirand(char *device) { struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; caddr_t inodebuf; ssize_t ibufsize; struct fs *sblock; ino_t inumber; ufs2_daddr_t sblockloc, dblk; char sbuf[SBLOCKSIZE], sbuftmp[SBLOCKSIZE]; int i, devfd, n, cg; u_int32_t bsize = DEV_BSIZE; - struct disklabel label; if ((devfd = open(device, printonly ? O_RDONLY : O_RDWR)) < 0) { warn("can't open %s", device); return (1); - } - - /* Get block size (usually 512) from disklabel if possible */ - if (!ignorelabel) { - if (ioctl(devfd, DIOCGDINFO, &label) < 0) - warn("can't read disklabel, using sector size of %d", - bsize); - else - bsize = label.d_secsize; } dp1 = NULL; dp2 = NULL; /* Read in master superblock */ (void)memset(&sbuf, 0, sizeof(sbuf)); sblock = (struct fs *)&sbuf; for (i = 0; sblock_try[i] != -1; i++) { sblockloc = sblock_try[i]; if (lseek(devfd, sblockloc, SEEK_SET) == -1) { warn("can't seek to superblock (%jd) on %s", (intmax_t)sblockloc, device); return (1); } if ((n = read(devfd, (void *)sblock, SBLOCKSIZE))!=SBLOCKSIZE) { warnx("can't read superblock on %s: %s", device, (n < SBLOCKSIZE) ? "short read" : strerror(errno)); return (1); } if ((sblock->fs_magic == FS_UFS1_MAGIC || (sblock->fs_magic == FS_UFS2_MAGIC && sblock->fs_sblockloc == sblock_try[i])) && sblock->fs_bsize <= MAXBSIZE && sblock->fs_bsize >= (ssize_t)sizeof(struct fs)) break; } if (sblock_try[i] == -1) { fprintf(stderr, "Cannot find file system superblock\n"); return (1); } if (sblock->fs_magic == FS_UFS1_MAGIC && sblock->fs_old_inodefmt < FS_44INODEFMT) { warnx("file system format is too old, sorry"); return (1); } if (!force && !printonly && sblock->fs_clean != 1) { warnx("file system is not clean, fsck %s first", device); return (1); } /* Make sure backup superblocks are sane. */ sblock = (struct fs *)&sbuftmp; for (cg = 0; cg < (int)sblock->fs_ncg; cg++) { dblk = fsbtodb(sblock, cgsblock(sblock, cg)); if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { warn("can't seek to %jd", (intmax_t)dblk * bsize); return (1); } else if ((n = write(devfd, (void *)sblock, SBLOCKSIZE)) != SBLOCKSIZE) { warn("can't read backup superblock %d on %s: %s", cg + 1, device, (n < SBLOCKSIZE) ? "short write" : strerror(errno)); return (1); } if (sblock->fs_magic != FS_UFS1_MAGIC && sblock->fs_magic != FS_UFS2_MAGIC) { warnx("bad magic number in backup superblock %d on %s", cg + 1, device); return (1); } if (sblock->fs_sbsize > SBLOCKSIZE) { warnx("size of backup superblock %d on %s is preposterous", cg + 1, device); return (1); } } sblock = (struct fs *)&sbuf; /* XXX - should really cap buffer at 512kb or so */ if (sblock->fs_magic == FS_UFS1_MAGIC) ibufsize = sizeof(struct ufs1_dinode) * sblock->fs_ipg; else ibufsize = sizeof(struct ufs2_dinode) * sblock->fs_ipg; if ((inodebuf = malloc(ibufsize)) == NULL) errx(1, "can't allocate memory for inode buffer"); if (printonly && (sblock->fs_id[0] || sblock->fs_id[1])) { if (sblock->fs_id[0]) (void)printf("%s was randomized on %s", device, ctime((void *)&(sblock->fs_id[0]))); (void)printf("fsid: %x %x\n", sblock->fs_id[0], sblock->fs_id[1]); } /* Randomize fs_id unless old 4.2BSD file system */ if (!printonly) { /* Randomize fs_id and write out new sblock and backups */ sblock->fs_id[0] = (u_int32_t)time(NULL); sblock->fs_id[1] = random(); if (lseek(devfd, sblockloc, SEEK_SET) == -1) { warn("can't seek to superblock (%jd) on %s", (intmax_t)sblockloc, device); return (1); } if ((n = write(devfd, (void *)sblock, SBLOCKSIZE)) != SBLOCKSIZE) { warn("can't write superblock on %s: %s", device, (n < SBLOCKSIZE) ? "short write" : strerror(errno)); return (1); } } /* For each cylinder group, randomize inodes and update backup sblock */ for (cg = 0, inumber = 0; cg < (int)sblock->fs_ncg; cg++) { /* Update superblock if appropriate */ if (!printonly) { dblk = fsbtodb(sblock, cgsblock(sblock, cg)); if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { warn("can't seek to %jd", (intmax_t)dblk * bsize); return (1); } else if ((n = write(devfd, (void *)sblock, SBLOCKSIZE)) != SBLOCKSIZE) { warn("can't write backup superblock %d on %s: %s", cg + 1, device, (n < SBLOCKSIZE) ? "short write" : strerror(errno)); return (1); } } /* Read in inodes, then print or randomize generation nums */ dblk = fsbtodb(sblock, ino_to_fsba(sblock, inumber)); if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { warn("can't seek to %jd", (intmax_t)dblk * bsize); return (1); } else if ((n = read(devfd, inodebuf, ibufsize)) != ibufsize) { warnx("can't read inodes: %s", (n < ibufsize) ? "short read" : strerror(errno)); return (1); } for (n = 0; n < (int)sblock->fs_ipg; n++, inumber++) { if (sblock->fs_magic == FS_UFS1_MAGIC) dp1 = &((struct ufs1_dinode *)inodebuf)[n]; else dp2 = &((struct ufs2_dinode *)inodebuf)[n]; if (inumber >= ROOTINO) { if (printonly) (void)printf("ino %ju gen %08x\n", (uintmax_t)inumber, sblock->fs_magic == FS_UFS1_MAGIC ? dp1->di_gen : dp2->di_gen); else if (sblock->fs_magic == FS_UFS1_MAGIC) dp1->di_gen = random(); else dp2->di_gen = random(); } } /* Write out modified inodes */ if (!printonly) { if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { warn("can't seek to %jd", (intmax_t)dblk * bsize); return (1); } else if ((n = write(devfd, inodebuf, ibufsize)) != ibufsize) { warnx("can't write inodes: %s", (n != ibufsize) ? "short write" : strerror(errno)); return (1); } } } (void)close(devfd); return(0); } static void usage(void) { (void)fprintf(stderr, "usage: fsirand [-b] [-f] [-p] special [special ...]\n"); exit(1); } Index: head/sbin/newfs/newfs.c =================================================================== --- head/sbin/newfs/newfs.c (revision 276736) +++ head/sbin/newfs/newfs.c (revision 276737) @@ -1,539 +1,509 @@ /* * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Marshall * Kirk McKusick and Network Associates Laboratories, the Security * Research Division of Network Associates, Inc. under DARPA/SPAWAR * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS * research program. * * Copyright (c) 1983, 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1983, 1989, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)newfs.c 8.13 (Berkeley) 5/1/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); /* * newfs: friendly front end to mkfs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "newfs.h" int Eflag; /* Erase previous disk contents */ int Lflag; /* add a volume label */ int Nflag; /* run without writing file system */ int Oflag = 2; /* file system format (1 => UFS1, 2 => UFS2) */ int Rflag; /* regression test */ int Uflag; /* enable soft updates for file system */ int jflag; /* enable soft updates journaling for filesys */ int Xflag = 0; /* exit in middle of newfs for testing */ int Jflag; /* enable gjournal for file system */ int lflag; /* enable multilabel for file system */ int nflag; /* do not create .snap directory */ int tflag; /* enable TRIM */ intmax_t fssize; /* file system size */ off_t mediasize; /* device size */ int sectorsize; /* bytes/sector */ int realsectorsize; /* bytes/sector in hardware */ int fsize = 0; /* fragment size */ int bsize = 0; /* block size */ int maxbsize = 0; /* maximum clustering */ int maxblkspercg = MAXBLKSPERCG; /* maximum blocks per cylinder group */ int minfree = MINFREE; /* free space threshold */ int metaspace; /* space held for metadata blocks */ int opt = DEFAULTOPT; /* optimization preference (space or time) */ int density; /* number of bytes per inode */ int maxcontig = 0; /* max contiguous blocks to allocate */ int maxbpg; /* maximum blocks per file in a cyl group */ int avgfilesize = AVFILESIZ;/* expected average file size */ int avgfilesperdir = AFPDIR;/* expected number of files per directory */ u_char *volumelabel = NULL; /* volume label for filesystem */ struct uufsd disk; /* libufs disk structure */ static char device[MAXPATHLEN]; static u_char bootarea[BBSIZE]; static int is_file; /* work on a file, not a device */ static char *dkname; static char *disktype; -static int unlabeled; static void getfssize(intmax_t *, const char *p, intmax_t, intmax_t); static struct disklabel *getdisklabel(char *s); -static void rewritelabel(char *s, struct disklabel *lp); static void usage(void); static int expand_number_int(const char *buf, int *num); ufs2_daddr_t part_ofs; /* partition offset in blocks, used with files */ int main(int argc, char *argv[]) { struct partition *pp; struct disklabel *lp; struct partition oldpartition; struct stat st; char *cp, *special; intmax_t reserved; int ch, i, rval; char part_name; /* partition name, default to full disk */ part_name = 'c'; reserved = 0; while ((ch = getopt(argc, argv, "EJL:NO:RS:T:UXa:b:c:d:e:f:g:h:i:jk:lm:no:p:r:s:t")) != -1) switch (ch) { case 'E': Eflag = 1; break; case 'J': Jflag = 1; break; case 'L': volumelabel = optarg; i = -1; while (isalnum(volumelabel[++i])); if (volumelabel[i] != '\0') { errx(1, "bad volume label. Valid characters are alphanumerics."); } if (strlen(volumelabel) >= MAXVOLLEN) { errx(1, "bad volume label. Length is longer than %d.", MAXVOLLEN); } Lflag = 1; break; case 'N': Nflag = 1; break; case 'O': if ((Oflag = atoi(optarg)) < 1 || Oflag > 2) errx(1, "%s: bad file system format value", optarg); break; case 'R': Rflag = 1; break; case 'S': rval = expand_number_int(optarg, §orsize); if (rval < 0 || sectorsize <= 0) errx(1, "%s: bad sector size", optarg); break; case 'T': disktype = optarg; break; case 'j': jflag = 1; /* fall through to enable soft updates */ case 'U': Uflag = 1; break; case 'X': Xflag++; break; case 'a': rval = expand_number_int(optarg, &maxcontig); if (rval < 0 || maxcontig <= 0) errx(1, "%s: bad maximum contiguous blocks", optarg); break; case 'b': rval = expand_number_int(optarg, &bsize); if (rval < 0) errx(1, "%s: bad block size", optarg); if (bsize < MINBSIZE) errx(1, "%s: block size too small, min is %d", optarg, MINBSIZE); if (bsize > MAXBSIZE) errx(1, "%s: block size too large, max is %d", optarg, MAXBSIZE); break; case 'c': rval = expand_number_int(optarg, &maxblkspercg); if (rval < 0 || maxblkspercg <= 0) errx(1, "%s: bad blocks per cylinder group", optarg); break; case 'd': rval = expand_number_int(optarg, &maxbsize); if (rval < 0 || maxbsize < MINBSIZE) errx(1, "%s: bad extent block size", optarg); break; case 'e': rval = expand_number_int(optarg, &maxbpg); if (rval < 0 || maxbpg <= 0) errx(1, "%s: bad blocks per file in a cylinder group", optarg); break; case 'f': rval = expand_number_int(optarg, &fsize); if (rval < 0 || fsize <= 0) errx(1, "%s: bad fragment size", optarg); break; case 'g': rval = expand_number_int(optarg, &avgfilesize); if (rval < 0 || avgfilesize <= 0) errx(1, "%s: bad average file size", optarg); break; case 'h': rval = expand_number_int(optarg, &avgfilesperdir); if (rval < 0 || avgfilesperdir <= 0) errx(1, "%s: bad average files per dir", optarg); break; case 'i': rval = expand_number_int(optarg, &density); if (rval < 0 || density <= 0) errx(1, "%s: bad bytes per inode", optarg); break; case 'l': lflag = 1; break; case 'k': if ((metaspace = atoi(optarg)) < 0) errx(1, "%s: bad metadata space %%", optarg); if (metaspace == 0) /* force to stay zero in mkfs */ metaspace = -1; break; case 'm': if ((minfree = atoi(optarg)) < 0 || minfree > 99) errx(1, "%s: bad free space %%", optarg); break; case 'n': nflag = 1; break; case 'o': if (strcmp(optarg, "space") == 0) opt = FS_OPTSPACE; else if (strcmp(optarg, "time") == 0) opt = FS_OPTTIME; else errx(1, "%s: unknown optimization preference: use `space' or `time'", optarg); break; case 'r': errno = 0; reserved = strtoimax(optarg, &cp, 0); if (errno != 0 || cp == optarg || *cp != '\0' || reserved < 0) errx(1, "%s: bad reserved size", optarg); break; case 'p': is_file = 1; part_name = optarg[0]; break; case 's': errno = 0; fssize = strtoimax(optarg, &cp, 0); if (errno != 0 || cp == optarg || *cp != '\0' || fssize < 0) errx(1, "%s: bad file system size", optarg); break; case 't': tflag = 1; break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc != 1) usage(); special = argv[0]; if (!special[0]) err(1, "empty file/special name"); cp = strrchr(special, '/'); if (cp == 0) { /* * No path prefix; try prefixing _PATH_DEV. */ snprintf(device, sizeof(device), "%s%s", _PATH_DEV, special); special = device; } if (is_file) { /* bypass ufs_disk_fillout_blank */ bzero( &disk, sizeof(disk)); disk.d_bsize = 1; disk.d_name = special; disk.d_fd = open(special, O_RDONLY); if (disk.d_fd < 0 || (!Nflag && ufs_disk_write(&disk) == -1)) errx(1, "%s: ", special); } else if (ufs_disk_fillout_blank(&disk, special) == -1 || (!Nflag && ufs_disk_write(&disk) == -1)) { if (disk.d_error != NULL) errx(1, "%s: %s", special, disk.d_error); else err(1, "%s", special); } if (fstat(disk.d_fd, &st) < 0) err(1, "%s", special); if ((st.st_mode & S_IFMT) != S_IFCHR) { warn("%s: not a character-special device", special); is_file = 1; /* assume it is a file */ dkname = special; if (sectorsize == 0) sectorsize = 512; mediasize = st.st_size; /* set fssize from the partition */ } else { if (sectorsize == 0) if (ioctl(disk.d_fd, DIOCGSECTORSIZE, §orsize) == -1) sectorsize = 0; /* back out on error for safety */ if (sectorsize && ioctl(disk.d_fd, DIOCGMEDIASIZE, &mediasize) != -1) getfssize(&fssize, special, mediasize / sectorsize, reserved); } pp = NULL; lp = getdisklabel(special); if (lp != NULL) { if (!is_file) /* already set for files */ part_name = special[strlen(special) - 1]; if ((part_name < 'a' || part_name - 'a' >= MAXPARTITIONS) && !isdigit(part_name)) errx(1, "%s: can't figure out file system partition", special); cp = &part_name; if (isdigit(*cp)) pp = &lp->d_partitions[RAW_PART]; else pp = &lp->d_partitions[*cp - 'a']; oldpartition = *pp; if (pp->p_size == 0) errx(1, "%s: `%c' partition is unavailable", special, *cp); if (pp->p_fstype == FS_BOOT) errx(1, "%s: `%c' partition overlaps boot program", special, *cp); getfssize(&fssize, special, pp->p_size, reserved); if (sectorsize == 0) sectorsize = lp->d_secsize; if (fsize == 0) fsize = pp->p_fsize; if (bsize == 0) bsize = pp->p_frag * pp->p_fsize; if (is_file) part_ofs = pp->p_offset; } if (sectorsize <= 0) errx(1, "%s: no default sector size", special); if (fsize <= 0) fsize = MAX(DFL_FRAGSIZE, sectorsize); if (bsize <= 0) bsize = MIN(DFL_BLKSIZE, 8 * fsize); if (minfree < MINFREE && opt != FS_OPTSPACE) { fprintf(stderr, "Warning: changing optimization to space "); fprintf(stderr, "because minfree is less than %d%%\n", MINFREE); opt = FS_OPTSPACE; } realsectorsize = sectorsize; if (sectorsize != DEV_BSIZE) { /* XXX */ int secperblk = sectorsize / DEV_BSIZE; sectorsize = DEV_BSIZE; fssize *= secperblk; if (pp != NULL) pp->p_size *= secperblk; } mkfs(pp, special); - if (!unlabeled) { - if (realsectorsize != DEV_BSIZE) - pp->p_size /= realsectorsize / DEV_BSIZE; - if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition))) - rewritelabel(special, lp); - } ufs_disk_close(&disk); if (!jflag) exit(0); if (execlp("tunefs", "newfs", "-j", "enable", special, NULL) < 0) err(1, "Cannot enable soft updates journaling, tunefs"); /* NOT REACHED */ } void getfssize(intmax_t *fsz, const char *s, intmax_t disksize, intmax_t reserved) { intmax_t available; available = disksize - reserved; if (available <= 0) errx(1, "%s: reserved not less than device size %jd", s, disksize); if (*fsz == 0) *fsz = available; else if (*fsz > available) errx(1, "%s: maximum file system size is %jd", s, available); } struct disklabel * getdisklabel(char *s) { static struct disklabel lab; struct disklabel *lp; if (is_file) { if (read(disk.d_fd, bootarea, BBSIZE) != BBSIZE) err(4, "cannot read bootarea"); if (bsd_disklabel_le_dec( bootarea + (0 /* labeloffset */ + 1 /* labelsoffset */ * sectorsize), &lab, MAXPARTITIONS)) errx(1, "no valid label found"); lp = &lab; return &lab; } - if (ioctl(disk.d_fd, DIOCGDINFO, (char *)&lab) != -1) - return (&lab); - unlabeled++; if (disktype) { lp = getdiskbyname(disktype); if (lp != NULL) return (lp); } return (NULL); -} - -void -rewritelabel(char *s, struct disklabel *lp) -{ - if (unlabeled) - return; - lp->d_checksum = 0; - lp->d_checksum = dkcksum(lp); - if (is_file) { - bsd_disklabel_le_enc(bootarea + 0 /* labeloffset */ + - 1 /* labelsoffset */ * sectorsize, lp); - lseek(disk.d_fd, 0, SEEK_SET); - if (write(disk.d_fd, bootarea, BBSIZE) != BBSIZE) - errx(1, "cannot write label"); - return; - } - if (ioctl(disk.d_fd, DIOCWDINFO, (char *)lp) == -1) - warn("ioctl (WDINFO): %s: can't rewrite disk label", s); } static void usage() { fprintf(stderr, "usage: %s [ -fsoptions ] special-device%s\n", getprogname(), " [device-type]"); fprintf(stderr, "where fsoptions are:\n"); fprintf(stderr, "\t-E Erase previous disk content\n"); fprintf(stderr, "\t-J Enable journaling via gjournal\n"); fprintf(stderr, "\t-L volume label to add to superblock\n"); fprintf(stderr, "\t-N do not create file system, just print out parameters\n"); fprintf(stderr, "\t-O file system format: 1 => UFS1, 2 => UFS2\n"); fprintf(stderr, "\t-R regression test, suppress random factors\n"); fprintf(stderr, "\t-S sector size\n"); fprintf(stderr, "\t-T disktype\n"); fprintf(stderr, "\t-U enable soft updates\n"); fprintf(stderr, "\t-a maximum contiguous blocks\n"); fprintf(stderr, "\t-b block size\n"); fprintf(stderr, "\t-c blocks per cylinders group\n"); fprintf(stderr, "\t-d maximum extent size\n"); fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n"); fprintf(stderr, "\t-f frag size\n"); fprintf(stderr, "\t-g average file size\n"); fprintf(stderr, "\t-h average files per directory\n"); fprintf(stderr, "\t-i number of bytes per inode\n"); fprintf(stderr, "\t-j enable soft updates journaling\n"); fprintf(stderr, "\t-k space to hold for metadata blocks\n"); fprintf(stderr, "\t-l enable multilabel MAC\n"); fprintf(stderr, "\t-n do not create .snap directory\n"); fprintf(stderr, "\t-m minimum free space %%\n"); fprintf(stderr, "\t-o optimization preference (`space' or `time')\n"); fprintf(stderr, "\t-p partition name (a..h)\n"); fprintf(stderr, "\t-r reserved sectors at the end of device\n"); fprintf(stderr, "\t-s file system size (sectors)\n"); fprintf(stderr, "\t-t enable TRIM\n"); exit(1); } static int expand_number_int(const char *buf, int *num) { int64_t num64; int rval; rval = expand_number(buf, &num64); if (rval < 0) return (rval); if (num64 > INT_MAX || num64 < INT_MIN) { errno = ERANGE; return (-1); } *num = (int)num64; return (0); } Index: head/sbin/newfs_msdos/newfs_msdos.c =================================================================== --- head/sbin/newfs_msdos/newfs_msdos.c (revision 276736) +++ head/sbin/newfs_msdos/newfs_msdos.c (revision 276737) @@ -1,1063 +1,1061 @@ /* * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXU16 0xffff /* maximum unsigned 16-bit quantity */ #define BPN 4 /* bits per nibble */ #define NPB 2 /* nibbles per byte */ #define DOSMAGIC 0xaa55 /* DOS magic number */ #define MINBPS 512 /* minimum bytes per sector */ #define MAXSPC 128 /* maximum sectors per cluster */ #define MAXNFT 16 /* maximum number of FATs */ #define DEFBLK 4096 /* default block size */ #define DEFBLK16 2048 /* default block size FAT16 */ #define DEFRDE 512 /* default root directory entries */ #define RESFTE 2 /* reserved FAT entries */ #define MINCLS12 1U /* minimum FAT12 clusters */ #define MINCLS16 0xff5U /* minimum FAT16 clusters */ #define MINCLS32 0xfff5U /* minimum FAT32 clusters */ #define MAXCLS12 0xff4U /* maximum FAT12 clusters */ #define MAXCLS16 0xfff4U /* maximum FAT16 clusters */ #define MAXCLS32 0xffffff4U /* maximum FAT32 clusters */ #define mincls(fat) ((fat) == 12 ? MINCLS12 : \ (fat) == 16 ? MINCLS16 : \ MINCLS32) #define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \ (fat) == 16 ? MAXCLS16 : \ MAXCLS32) #define mk1(p, x) \ (p) = (u_int8_t)(x) #define mk2(p, x) \ (p)[0] = (u_int8_t)(x), \ (p)[1] = (u_int8_t)((x) >> 010) #define mk4(p, x) \ (p)[0] = (u_int8_t)(x), \ (p)[1] = (u_int8_t)((x) >> 010), \ (p)[2] = (u_int8_t)((x) >> 020), \ (p)[3] = (u_int8_t)((x) >> 030) #define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg) #define argto2(arg, lo, msg) argtou(arg, lo, 0xffff, msg) #define argto4(arg, lo, msg) argtou(arg, lo, 0xffffffff, msg) #define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg) struct bs { u_int8_t bsJump[3]; /* bootstrap entry point */ u_int8_t bsOemName[8]; /* OEM name and version */ } __packed; struct bsbpb { u_int8_t bpbBytesPerSec[2]; /* bytes per sector */ u_int8_t bpbSecPerClust; /* sectors per cluster */ u_int8_t bpbResSectors[2]; /* reserved sectors */ u_int8_t bpbFATs; /* number of FATs */ u_int8_t bpbRootDirEnts[2]; /* root directory entries */ u_int8_t bpbSectors[2]; /* total sectors */ u_int8_t bpbMedia; /* media descriptor */ u_int8_t bpbFATsecs[2]; /* sectors per FAT */ u_int8_t bpbSecPerTrack[2]; /* sectors per track */ u_int8_t bpbHeads[2]; /* drive heads */ u_int8_t bpbHiddenSecs[4]; /* hidden sectors */ u_int8_t bpbHugeSectors[4]; /* big total sectors */ } __packed; struct bsxbpb { u_int8_t bpbBigFATsecs[4]; /* big sectors per FAT */ u_int8_t bpbExtFlags[2]; /* FAT control flags */ u_int8_t bpbFSVers[2]; /* file system version */ u_int8_t bpbRootClust[4]; /* root directory start cluster */ u_int8_t bpbFSInfo[2]; /* file system info sector */ u_int8_t bpbBackup[2]; /* backup boot sector */ u_int8_t bpbReserved[12]; /* reserved */ } __packed; struct bsx { u_int8_t exDriveNumber; /* drive number */ u_int8_t exReserved1; /* reserved */ u_int8_t exBootSignature; /* extended boot signature */ u_int8_t exVolumeID[4]; /* volume ID number */ u_int8_t exVolumeLabel[11]; /* volume label */ u_int8_t exFileSysType[8]; /* file system type */ } __packed; struct de { u_int8_t deName[11]; /* name and extension */ u_int8_t deAttributes; /* attributes */ u_int8_t rsvd[10]; /* reserved */ u_int8_t deMTime[2]; /* last-modified time */ u_int8_t deMDate[2]; /* last-modified date */ u_int8_t deStartCluster[2]; /* starting cluster */ u_int8_t deFileSize[4]; /* size */ } __packed; struct bpb { u_int bpbBytesPerSec; /* bytes per sector */ u_int bpbSecPerClust; /* sectors per cluster */ u_int bpbResSectors; /* reserved sectors */ u_int bpbFATs; /* number of FATs */ u_int bpbRootDirEnts; /* root directory entries */ u_int bpbSectors; /* total sectors */ u_int bpbMedia; /* media descriptor */ u_int bpbFATsecs; /* sectors per FAT */ u_int bpbSecPerTrack; /* sectors per track */ u_int bpbHeads; /* drive heads */ u_int bpbHiddenSecs; /* hidden sectors */ u_int bpbHugeSectors; /* big total sectors */ u_int bpbBigFATsecs; /* big sectors per FAT */ u_int bpbRootClust; /* root directory start cluster */ u_int bpbFSInfo; /* file system info sector */ u_int bpbBackup; /* backup boot sector */ }; #define BPBGAP 0, 0, 0, 0, 0, 0 static struct { const char *name; struct bpb bpb; } const stdfmt[] = { {"160", {512, 1, 1, 2, 64, 320, 0xfe, 1, 8, 1, BPBGAP}}, {"180", {512, 1, 1, 2, 64, 360, 0xfc, 2, 9, 1, BPBGAP}}, {"320", {512, 2, 1, 2, 112, 640, 0xff, 1, 8, 2, BPBGAP}}, {"360", {512, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2, BPBGAP}}, {"640", {512, 2, 1, 2, 112, 1280, 0xfb, 2, 8, 2, BPBGAP}}, {"720", {512, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2, BPBGAP}}, {"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, BPBGAP}}, {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2, 8, 2, BPBGAP}}, {"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, BPBGAP}}, {"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2, BPBGAP}} }; static const u_int8_t bootcode[] = { 0xfa, /* cli */ 0x31, 0xc0, /* xor ax,ax */ 0x8e, 0xd0, /* mov ss,ax */ 0xbc, 0x00, 0x7c, /* mov sp,7c00h */ 0xfb, /* sti */ 0x8e, 0xd8, /* mov ds,ax */ 0xe8, 0x00, 0x00, /* call $ + 3 */ 0x5e, /* pop si */ 0x83, 0xc6, 0x19, /* add si,+19h */ 0xbb, 0x07, 0x00, /* mov bx,0007h */ 0xfc, /* cld */ 0xac, /* lodsb */ 0x84, 0xc0, /* test al,al */ 0x74, 0x06, /* jz $ + 8 */ 0xb4, 0x0e, /* mov ah,0eh */ 0xcd, 0x10, /* int 10h */ 0xeb, 0xf5, /* jmp $ - 9 */ 0x30, 0xe4, /* xor ah,ah */ 0xcd, 0x16, /* int 16h */ 0xcd, 0x19, /* int 19h */ 0x0d, 0x0a, 'N', 'o', 'n', '-', 's', 'y', 's', 't', 'e', 'm', ' ', 'd', 'i', 's', 'k', 0x0d, 0x0a, 'P', 'r', 'e', 's', 's', ' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y', ' ', 't', 'o', ' ', 'r', 'e', 'b', 'o', 'o', 't', 0x0d, 0x0a, 0 }; static volatile sig_atomic_t got_siginfo; static void infohandler(int); static void check_mounted(const char *, mode_t); static void getstdfmt(const char *, struct bpb *); static void getdiskinfo(int, const char *, const char *, int, struct bpb *); static void print_bpb(struct bpb *); static u_int ckgeom(const char *, u_int, const char *); static u_int argtou(const char *, u_int, u_int, const char *); static off_t argtooff(const char *, const char *); static int oklabel(const char *); static void mklabel(u_int8_t *, const char *); static void setstr(u_int8_t *, const char *, size_t); static void usage(void); /* * Construct a FAT12, FAT16, or FAT32 file system. */ int main(int argc, char *argv[]) { static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:"; const char *opt_B = NULL, *opt_L = NULL, *opt_O = NULL, *opt_f = NULL; u_int opt_F = 0, opt_I = 0, opt_S = 0, opt_a = 0, opt_b = 0, opt_c = 0; u_int opt_e = 0, opt_h = 0, opt_i = 0, opt_k = 0, opt_m = 0, opt_n = 0; u_int opt_o = 0, opt_r = 0, opt_s = 0, opt_u = 0; int opt_N = 0; int Iflag = 0, mflag = 0, oflag = 0; char buf[MAXPATHLEN]; struct sigaction si_sa; struct stat sb; struct timeval tv; struct bpb bpb; struct tm *tm; struct bs *bs; struct bsbpb *bsbpb; struct bsxbpb *bsxbpb; struct bsx *bsx; struct de *de; u_int8_t *img; const char *fname, *dtype, *bname; ssize_t n; time_t now; u_int fat, bss, rds, cls, dir, lsn, x, x1, x2; int ch, fd, fd1; off_t opt_create = 0, opt_ofs = 0; while ((ch = getopt(argc, argv, opts)) != -1) switch (ch) { case '@': opt_ofs = argtooff(optarg, "offset"); break; case 'N': opt_N = 1; break; case 'B': opt_B = optarg; break; case 'C': opt_create = argtooff(optarg, "create size"); break; case 'F': if (strcmp(optarg, "12") && strcmp(optarg, "16") && strcmp(optarg, "32")) errx(1, "%s: bad FAT type", optarg); opt_F = atoi(optarg); break; case 'I': opt_I = argto4(optarg, 0, "volume ID"); Iflag = 1; break; case 'L': if (!oklabel(optarg)) errx(1, "%s: bad volume label", optarg); opt_L = optarg; break; case 'O': if (strlen(optarg) > 8) errx(1, "%s: bad OEM string", optarg); opt_O = optarg; break; case 'S': opt_S = argto2(optarg, 1, "bytes/sector"); break; case 'a': opt_a = argto4(optarg, 1, "sectors/FAT"); break; case 'b': opt_b = argtox(optarg, 1, "block size"); opt_c = 0; break; case 'c': opt_c = argto1(optarg, 1, "sectors/cluster"); opt_b = 0; break; case 'e': opt_e = argto2(optarg, 1, "directory entries"); break; case 'f': opt_f = optarg; break; case 'h': opt_h = argto2(optarg, 1, "drive heads"); break; case 'i': opt_i = argto2(optarg, 1, "info sector"); break; case 'k': opt_k = argto2(optarg, 1, "backup sector"); break; case 'm': opt_m = argto1(optarg, 0, "media descriptor"); mflag = 1; break; case 'n': opt_n = argto1(optarg, 1, "number of FATs"); break; case 'o': opt_o = argto4(optarg, 0, "hidden sectors"); oflag = 1; break; case 'r': opt_r = argto2(optarg, 1, "reserved sectors"); break; case 's': opt_s = argto4(optarg, 1, "file system size"); break; case 'u': opt_u = argto2(optarg, 1, "sectors/track"); break; default: usage(); } argc -= optind; argv += optind; if (argc < 1 || argc > 2) usage(); fname = *argv++; if (!opt_create && !strchr(fname, '/')) { snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); if (!(fname = strdup(buf))) err(1, NULL); } dtype = *argv; if (opt_create) { if (opt_N) errx(1, "create (-C) is incompatible with -N"); fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644); if (fd == -1) errx(1, "failed to create %s", fname); if (ftruncate(fd, opt_create)) errx(1, "failed to initialize %jd bytes", (intmax_t)opt_create); } else if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1) err(1, "%s", fname); if (fstat(fd, &sb)) err(1, "%s", fname); if (opt_create) { if (!S_ISREG(sb.st_mode)) warnx("warning, %s is not a regular file", fname); } else { if (!S_ISCHR(sb.st_mode)) warnx("warning, %s is not a character device", fname); } if (!opt_N) check_mounted(fname, sb.st_mode); if (opt_ofs && opt_ofs != lseek(fd, opt_ofs, SEEK_SET)) errx(1, "cannot seek to %jd", (intmax_t)opt_ofs); memset(&bpb, 0, sizeof(bpb)); if (opt_f) { getstdfmt(opt_f, &bpb); bpb.bpbHugeSectors = bpb.bpbSectors; bpb.bpbSectors = 0; bpb.bpbBigFATsecs = bpb.bpbFATsecs; bpb.bpbFATsecs = 0; } if (opt_h) bpb.bpbHeads = opt_h; if (opt_u) bpb.bpbSecPerTrack = opt_u; if (opt_S) bpb.bpbBytesPerSec = opt_S; if (opt_s) bpb.bpbHugeSectors = opt_s; if (oflag) bpb.bpbHiddenSecs = opt_o; if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) { off_t delta; getdiskinfo(fd, fname, dtype, oflag, &bpb); bpb.bpbHugeSectors -= (opt_ofs / bpb.bpbBytesPerSec); delta = bpb.bpbHugeSectors % bpb.bpbSecPerTrack; if (delta != 0) { warnx("trim %d sectors to adjust to a multiple of %d", (int)delta, bpb.bpbSecPerTrack); bpb.bpbHugeSectors -= delta; } if (bpb.bpbSecPerClust == 0) { /* set defaults */ if (bpb.bpbHugeSectors <= 6000) /* about 3MB -> 512 bytes */ bpb.bpbSecPerClust = 1; else if (bpb.bpbHugeSectors <= (1<<17)) /* 64M -> 4k */ bpb.bpbSecPerClust = 8; else if (bpb.bpbHugeSectors <= (1<<19)) /* 256M -> 8k */ bpb.bpbSecPerClust = 16; else if (bpb.bpbHugeSectors <= (1<<21)) /* 1G -> 16k */ bpb.bpbSecPerClust = 32; else bpb.bpbSecPerClust = 64; /* otherwise 32k */ } } if (!powerof2(bpb.bpbBytesPerSec)) errx(1, "bytes/sector (%u) is not a power of 2", bpb.bpbBytesPerSec); if (bpb.bpbBytesPerSec < MINBPS) errx(1, "bytes/sector (%u) is too small; minimum is %u", bpb.bpbBytesPerSec, MINBPS); if (!(fat = opt_F)) { if (opt_f) fat = 12; else if (!opt_e && (opt_i || opt_k)) fat = 32; } if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k))) errx(1, "-%c is not a legal FAT%s option", fat == 32 ? 'e' : opt_i ? 'i' : 'k', fat == 32 ? "32" : "12/16"); if (opt_f && fat == 32) bpb.bpbRootDirEnts = 0; if (opt_b) { if (!powerof2(opt_b)) errx(1, "block size (%u) is not a power of 2", opt_b); if (opt_b < bpb.bpbBytesPerSec) errx(1, "block size (%u) is too small; minimum is %u", opt_b, bpb.bpbBytesPerSec); if (opt_b > bpb.bpbBytesPerSec * MAXSPC) errx(1, "block size (%u) is too large; maximum is %u", opt_b, bpb.bpbBytesPerSec * MAXSPC); bpb.bpbSecPerClust = opt_b / bpb.bpbBytesPerSec; } if (opt_c) { if (!powerof2(opt_c)) errx(1, "sectors/cluster (%u) is not a power of 2", opt_c); bpb.bpbSecPerClust = opt_c; } if (opt_r) bpb.bpbResSectors = opt_r; if (opt_n) { if (opt_n > MAXNFT) errx(1, "number of FATs (%u) is too large; maximum is %u", opt_n, MAXNFT); bpb.bpbFATs = opt_n; } if (opt_e) bpb.bpbRootDirEnts = opt_e; if (mflag) { if (opt_m < 0xf0) errx(1, "illegal media descriptor (%#x)", opt_m); bpb.bpbMedia = opt_m; } if (opt_a) bpb.bpbBigFATsecs = opt_a; if (opt_i) bpb.bpbFSInfo = opt_i; if (opt_k) bpb.bpbBackup = opt_k; bss = 1; bname = NULL; fd1 = -1; if (opt_B) { bname = opt_B; if (!strchr(bname, '/')) { snprintf(buf, sizeof(buf), "/boot/%s", bname); if (!(bname = strdup(buf))) err(1, NULL); } if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb)) err(1, "%s", bname); if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bpbBytesPerSec || sb.st_size < bpb.bpbBytesPerSec || sb.st_size > bpb.bpbBytesPerSec * MAXU16) errx(1, "%s: inappropriate file type or format", bname); bss = sb.st_size / bpb.bpbBytesPerSec; } if (!bpb.bpbFATs) bpb.bpbFATs = 2; if (!fat) { if (bpb.bpbHugeSectors < (bpb.bpbResSectors ? bpb.bpbResSectors : bss) + howmany((RESFTE + (bpb.bpbSecPerClust ? MINCLS16 : MAXCLS12 + 1)) * (bpb.bpbSecPerClust ? 16 : 12) / BPN, bpb.bpbBytesPerSec * NPB) * bpb.bpbFATs + howmany(bpb.bpbRootDirEnts ? bpb.bpbRootDirEnts : DEFRDE, bpb.bpbBytesPerSec / sizeof(struct de)) + (bpb.bpbSecPerClust ? MINCLS16 : MAXCLS12 + 1) * (bpb.bpbSecPerClust ? bpb.bpbSecPerClust : howmany(DEFBLK, bpb.bpbBytesPerSec))) fat = 12; else if (bpb.bpbRootDirEnts || bpb.bpbHugeSectors < (bpb.bpbResSectors ? bpb.bpbResSectors : bss) + howmany((RESFTE + MAXCLS16) * 2, bpb.bpbBytesPerSec) * bpb.bpbFATs + howmany(DEFRDE, bpb.bpbBytesPerSec / sizeof(struct de)) + (MAXCLS16 + 1) * (bpb.bpbSecPerClust ? bpb.bpbSecPerClust : howmany(8192, bpb.bpbBytesPerSec))) fat = 16; else fat = 32; } x = bss; if (fat == 32) { if (!bpb.bpbFSInfo) { if (x == MAXU16 || x == bpb.bpbBackup) errx(1, "no room for info sector"); bpb.bpbFSInfo = x; } if (bpb.bpbFSInfo != MAXU16 && x <= bpb.bpbFSInfo) x = bpb.bpbFSInfo + 1; if (!bpb.bpbBackup) { if (x == MAXU16) errx(1, "no room for backup sector"); bpb.bpbBackup = x; } else if (bpb.bpbBackup != MAXU16 && bpb.bpbBackup == bpb.bpbFSInfo) errx(1, "backup sector would overwrite info sector"); if (bpb.bpbBackup != MAXU16 && x <= bpb.bpbBackup) x = bpb.bpbBackup + 1; } if (!bpb.bpbResSectors) bpb.bpbResSectors = fat == 32 ? MAX(x, MAX(16384 / bpb.bpbBytesPerSec, 4)) : x; else if (bpb.bpbResSectors < x) errx(1, "too few reserved sectors (need %d have %d)", x, bpb.bpbResSectors); if (fat != 32 && !bpb.bpbRootDirEnts) bpb.bpbRootDirEnts = DEFRDE; rds = howmany(bpb.bpbRootDirEnts, bpb.bpbBytesPerSec / sizeof(struct de)); if (!bpb.bpbSecPerClust) for (bpb.bpbSecPerClust = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bpbBytesPerSec); bpb.bpbSecPerClust < MAXSPC && bpb.bpbResSectors + howmany((RESFTE + maxcls(fat)) * (fat / BPN), bpb.bpbBytesPerSec * NPB) * bpb.bpbFATs + rds + (u_int64_t) (maxcls(fat) + 1) * bpb.bpbSecPerClust <= bpb.bpbHugeSectors; bpb.bpbSecPerClust <<= 1) continue; if (fat != 32 && bpb.bpbBigFATsecs > MAXU16) errx(1, "too many sectors/FAT for FAT12/16"); x1 = bpb.bpbResSectors + rds; x = bpb.bpbBigFATsecs ? bpb.bpbBigFATsecs : 1; if (x1 + (u_int64_t)x * bpb.bpbFATs > bpb.bpbHugeSectors) errx(1, "meta data exceeds file system size"); x1 += x * bpb.bpbFATs; x = (u_int64_t)(bpb.bpbHugeSectors - x1) * bpb.bpbBytesPerSec * NPB / (bpb.bpbSecPerClust * bpb.bpbBytesPerSec * NPB + fat / BPN * bpb.bpbFATs); x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), bpb.bpbBytesPerSec * NPB); if (!bpb.bpbBigFATsecs) { bpb.bpbBigFATsecs = x2; x1 += (bpb.bpbBigFATsecs - 1) * bpb.bpbFATs; } cls = (bpb.bpbHugeSectors - x1) / bpb.bpbSecPerClust; x = (u_int64_t)bpb.bpbBigFATsecs * bpb.bpbBytesPerSec * NPB / (fat / BPN) - RESFTE; if (cls > x) cls = x; if (bpb.bpbBigFATsecs < x2) warnx("warning: sectors/FAT limits file system to %u clusters", cls); if (cls < mincls(fat)) errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat, mincls(fat)); if (cls > maxcls(fat)) { cls = maxcls(fat); bpb.bpbHugeSectors = x1 + (cls + 1) * bpb.bpbSecPerClust - 1; warnx("warning: FAT type limits file system to %u sectors", bpb.bpbHugeSectors); } printf("%s: %u sector%s in %u FAT%u cluster%s " "(%u bytes/cluster)\n", fname, cls * bpb.bpbSecPerClust, cls * bpb.bpbSecPerClust == 1 ? "" : "s", cls, fat, cls == 1 ? "" : "s", bpb.bpbBytesPerSec * bpb.bpbSecPerClust); if (!bpb.bpbMedia) bpb.bpbMedia = !bpb.bpbHiddenSecs ? 0xf0 : 0xf8; if (fat == 32) bpb.bpbRootClust = RESFTE; if (bpb.bpbHiddenSecs + bpb.bpbHugeSectors <= MAXU16) { bpb.bpbSectors = bpb.bpbHugeSectors; bpb.bpbHugeSectors = 0; } if (fat != 32) { bpb.bpbFATsecs = bpb.bpbBigFATsecs; bpb.bpbBigFATsecs = 0; } print_bpb(&bpb); if (!opt_N) { gettimeofday(&tv, NULL); now = tv.tv_sec; tm = localtime(&now); if (!(img = malloc(bpb.bpbBytesPerSec))) err(1, NULL); dir = bpb.bpbResSectors + (bpb.bpbFATsecs ? bpb.bpbFATsecs : bpb.bpbBigFATsecs) * bpb.bpbFATs; memset(&si_sa, 0, sizeof(si_sa)); si_sa.sa_handler = infohandler; if (sigaction(SIGINFO, &si_sa, NULL) == -1) err(1, "sigaction SIGINFO"); for (lsn = 0; lsn < dir + (fat == 32 ? bpb.bpbSecPerClust : rds); lsn++) { if (got_siginfo) { fprintf(stderr,"%s: writing sector %u of %u (%u%%)\n", fname, lsn, (dir + (fat == 32 ? bpb.bpbSecPerClust: rds)), (lsn * 100) / (dir + (fat == 32 ? bpb.bpbSecPerClust: rds))); got_siginfo = 0; } x = lsn; if (opt_B && fat == 32 && bpb.bpbBackup != MAXU16 && bss <= bpb.bpbBackup && x >= bpb.bpbBackup) { x -= bpb.bpbBackup; if (!x && lseek(fd1, opt_ofs, SEEK_SET)) err(1, "%s", bname); } if (opt_B && x < bss) { if ((n = read(fd1, img, bpb.bpbBytesPerSec)) == -1) err(1, "%s", bname); if ((unsigned)n != bpb.bpbBytesPerSec) errx(1, "%s: can't read sector %u", bname, x); } else memset(img, 0, bpb.bpbBytesPerSec); if (!lsn || (fat == 32 && bpb.bpbBackup != MAXU16 && lsn == bpb.bpbBackup)) { x1 = sizeof(struct bs); bsbpb = (struct bsbpb *)(img + x1); mk2(bsbpb->bpbBytesPerSec, bpb.bpbBytesPerSec); mk1(bsbpb->bpbSecPerClust, bpb.bpbSecPerClust); mk2(bsbpb->bpbResSectors, bpb.bpbResSectors); mk1(bsbpb->bpbFATs, bpb.bpbFATs); mk2(bsbpb->bpbRootDirEnts, bpb.bpbRootDirEnts); mk2(bsbpb->bpbSectors, bpb.bpbSectors); mk1(bsbpb->bpbMedia, bpb.bpbMedia); mk2(bsbpb->bpbFATsecs, bpb.bpbFATsecs); mk2(bsbpb->bpbSecPerTrack, bpb.bpbSecPerTrack); mk2(bsbpb->bpbHeads, bpb.bpbHeads); mk4(bsbpb->bpbHiddenSecs, bpb.bpbHiddenSecs); mk4(bsbpb->bpbHugeSectors, bpb.bpbHugeSectors); x1 += sizeof(struct bsbpb); if (fat == 32) { bsxbpb = (struct bsxbpb *)(img + x1); mk4(bsxbpb->bpbBigFATsecs, bpb.bpbBigFATsecs); mk2(bsxbpb->bpbExtFlags, 0); mk2(bsxbpb->bpbFSVers, 0); mk4(bsxbpb->bpbRootClust, bpb.bpbRootClust); mk2(bsxbpb->bpbFSInfo, bpb.bpbFSInfo); mk2(bsxbpb->bpbBackup, bpb.bpbBackup); x1 += sizeof(struct bsxbpb); } bsx = (struct bsx *)(img + x1); mk1(bsx->exBootSignature, 0x29); if (Iflag) x = opt_I; else x = (((u_int)(1 + tm->tm_mon) << 8 | (u_int)tm->tm_mday) + ((u_int)tm->tm_sec << 8 | (u_int)(tv.tv_usec / 10))) << 16 | ((u_int)(1900 + tm->tm_year) + ((u_int)tm->tm_hour << 8 | (u_int)tm->tm_min)); mk4(bsx->exVolumeID, x); mklabel(bsx->exVolumeLabel, opt_L ? opt_L : "NO NAME"); sprintf(buf, "FAT%u", fat); setstr(bsx->exFileSysType, buf, sizeof(bsx->exFileSysType)); if (!opt_B) { x1 += sizeof(struct bsx); bs = (struct bs *)img; mk1(bs->bsJump[0], 0xeb); mk1(bs->bsJump[1], x1 - 2); mk1(bs->bsJump[2], 0x90); setstr(bs->bsOemName, opt_O ? opt_O : "BSD4.4 ", sizeof(bs->bsOemName)); memcpy(img + x1, bootcode, sizeof(bootcode)); mk2(img + MINBPS - 2, DOSMAGIC); } } else if (fat == 32 && bpb.bpbFSInfo != MAXU16 && (lsn == bpb.bpbFSInfo || (bpb.bpbBackup != MAXU16 && lsn == bpb.bpbBackup + bpb.bpbFSInfo))) { mk4(img, 0x41615252); mk4(img + MINBPS - 28, 0x61417272); mk4(img + MINBPS - 24, 0xffffffff); mk4(img + MINBPS - 20, bpb.bpbRootClust); mk2(img + MINBPS - 2, DOSMAGIC); } else if (lsn >= bpb.bpbResSectors && lsn < dir && !((lsn - bpb.bpbResSectors) % (bpb.bpbFATsecs ? bpb.bpbFATsecs : bpb.bpbBigFATsecs))) { mk1(img[0], bpb.bpbMedia); for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++) mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff); } else if (lsn == dir && opt_L) { de = (struct de *)img; mklabel(de->deName, opt_L); mk1(de->deAttributes, 050); x = (u_int)tm->tm_hour << 11 | (u_int)tm->tm_min << 5 | (u_int)tm->tm_sec >> 1; mk2(de->deMTime, x); x = (u_int)(tm->tm_year - 80) << 9 | (u_int)(tm->tm_mon + 1) << 5 | (u_int)tm->tm_mday; mk2(de->deMDate, x); } if ((n = write(fd, img, bpb.bpbBytesPerSec)) == -1) err(1, "%s", fname); if ((unsigned)n != bpb.bpbBytesPerSec) errx(1, "%s: can't write sector %u", fname, lsn); } } return 0; } /* * Exit with error if file system is mounted. */ static void check_mounted(const char *fname, mode_t mode) { struct statfs *mp; const char *s1, *s2; size_t len; int n, r; if (!(n = getmntinfo(&mp, MNT_NOWAIT))) err(1, "getmntinfo"); len = strlen(_PATH_DEV); s1 = fname; if (!strncmp(s1, _PATH_DEV, len)) s1 += len; r = S_ISCHR(mode) && s1 != fname && *s1 == 'r'; for (; n--; mp++) { s2 = mp->f_mntfromname; if (!strncmp(s2, _PATH_DEV, len)) s2 += len; if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) || !strcmp(s1, s2)) errx(1, "%s is mounted on %s", fname, mp->f_mntonname); } } /* * Get a standard format. */ static void getstdfmt(const char *fmt, struct bpb *bpb) { u_int x, i; x = sizeof(stdfmt) / sizeof(stdfmt[0]); for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++); if (i == x) errx(1, "%s: unknown standard format", fmt); *bpb = stdfmt[i].bpb; } /* * Get disk slice, partition, and geometry information. */ static void getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag, struct bpb *bpb) { struct disklabel *lp, dlp; struct fd_type type; off_t ms, hs = 0; lp = NULL; /* If the user specified a disk type, try to use that */ if (dtype != NULL) { lp = getdiskbyname(dtype); } /* Maybe it's a floppy drive */ if (lp == NULL) { if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) { struct stat st; if (fstat(fd, &st)) err(1, "cannot get disk size"); /* create a fake geometry for a file image */ ms = st.st_size; dlp.d_secsize = 512; dlp.d_nsectors = 63; dlp.d_ntracks = 255; dlp.d_secperunit = ms / dlp.d_secsize; lp = &dlp; } else if (ioctl(fd, FD_GTYPE, &type) != -1) { dlp.d_secsize = 128 << type.secsize; dlp.d_nsectors = type.sectrac; dlp.d_ntracks = type.heads; dlp.d_secperunit = ms / dlp.d_secsize; lp = &dlp; } } /* Maybe it's a fixed drive */ if (lp == NULL) { if (bpb->bpbBytesPerSec) dlp.d_secsize = bpb->bpbBytesPerSec; - if (ioctl(fd, DIOCGDINFO, &dlp) == -1) { - if (bpb->bpbBytesPerSec == 0 && ioctl(fd, DIOCGSECTORSIZE, - &dlp.d_secsize) == -1) - err(1, "cannot get sector size"); + if (bpb->bpbBytesPerSec == 0 && ioctl(fd, DIOCGSECTORSIZE, + &dlp.d_secsize) == -1) + err(1, "cannot get sector size"); - dlp.d_secperunit = ms / dlp.d_secsize; + dlp.d_secperunit = ms / dlp.d_secsize; - if (bpb->bpbSecPerTrack == 0 && ioctl(fd, DIOCGFWSECTORS, - &dlp.d_nsectors) == -1) { - warn("cannot get number of sectors per track"); - dlp.d_nsectors = 63; - } - if (bpb->bpbHeads == 0 && - ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) { - warn("cannot get number of heads"); - if (dlp.d_secperunit <= 63*1*1024) - dlp.d_ntracks = 1; - else if (dlp.d_secperunit <= 63*16*1024) - dlp.d_ntracks = 16; - else - dlp.d_ntracks = 255; - } + if (bpb->bpbSecPerTrack == 0 && ioctl(fd, DIOCGFWSECTORS, + &dlp.d_nsectors) == -1) { + warn("cannot get number of sectors per track"); + dlp.d_nsectors = 63; + } + if (bpb->bpbHeads == 0 && + ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) { + warn("cannot get number of heads"); + if (dlp.d_secperunit <= 63*1*1024) + dlp.d_ntracks = 1; + else if (dlp.d_secperunit <= 63*16*1024) + dlp.d_ntracks = 16; + else + dlp.d_ntracks = 255; } hs = (ms / dlp.d_secsize) - dlp.d_secperunit; lp = &dlp; } if (bpb->bpbBytesPerSec == 0) bpb->bpbBytesPerSec = ckgeom(fname, lp->d_secsize, "bytes/sector"); if (bpb->bpbSecPerTrack == 0) bpb->bpbSecPerTrack = ckgeom(fname, lp->d_nsectors, "sectors/track"); if (bpb->bpbHeads == 0) bpb->bpbHeads = ckgeom(fname, lp->d_ntracks, "drive heads"); if (bpb->bpbHugeSectors == 0) bpb->bpbHugeSectors = lp->d_secperunit; if (bpb->bpbHiddenSecs == 0) bpb->bpbHiddenSecs = hs; } /* * Print out BPB values. */ static void print_bpb(struct bpb *bpb) { printf("BytesPerSec=%u SecPerClust=%u ResSectors=%u FATs=%u", bpb->bpbBytesPerSec, bpb->bpbSecPerClust, bpb->bpbResSectors, bpb->bpbFATs); if (bpb->bpbRootDirEnts) printf(" RootDirEnts=%u", bpb->bpbRootDirEnts); if (bpb->bpbSectors) printf(" Sectors=%u", bpb->bpbSectors); printf(" Media=%#x", bpb->bpbMedia); if (bpb->bpbFATsecs) printf(" FATsecs=%u", bpb->bpbFATsecs); printf(" SecPerTrack=%u Heads=%u HiddenSecs=%u", bpb->bpbSecPerTrack, bpb->bpbHeads, bpb->bpbHiddenSecs); if (bpb->bpbHugeSectors) printf(" HugeSectors=%u", bpb->bpbHugeSectors); if (!bpb->bpbFATsecs) { printf(" FATsecs=%u RootCluster=%u", bpb->bpbBigFATsecs, bpb->bpbRootClust); printf(" FSInfo="); printf(bpb->bpbFSInfo == MAXU16 ? "%#x" : "%u", bpb->bpbFSInfo); printf(" Backup="); printf(bpb->bpbBackup == MAXU16 ? "%#x" : "%u", bpb->bpbBackup); } printf("\n"); } /* * Check a disk geometry value. */ static u_int ckgeom(const char *fname, u_int val, const char *msg) { if (!val) errx(1, "%s: no default %s", fname, msg); if (val > MAXU16) errx(1, "%s: illegal %s %d", fname, msg, val); return val; } /* * Convert and check a numeric option argument. */ static u_int argtou(const char *arg, u_int lo, u_int hi, const char *msg) { char *s; u_long x; errno = 0; x = strtoul(arg, &s, 0); if (errno || !*arg || *s || x < lo || x > hi) errx(1, "%s: bad %s", arg, msg); return x; } /* * Same for off_t, with optional skmgpP suffix */ static off_t argtooff(const char *arg, const char *msg) { char *s; off_t x; errno = 0; x = strtoll(arg, &s, 0); /* allow at most one extra char */ if (errno || x < 0 || (s[0] && s[1]) ) errx(1, "%s: bad %s", arg, msg); if (*s) { /* the extra char is the multiplier */ switch (*s) { default: errx(1, "%s: bad %s", arg, msg); /* notreached */ case 's': /* sector */ case 'S': x <<= 9; /* times 512 */ break; case 'k': /* kilobyte */ case 'K': x <<= 10; /* times 1024 */ break; case 'm': /* megabyte */ case 'M': x <<= 20; /* times 1024*1024 */ break; case 'g': /* gigabyte */ case 'G': x <<= 30; /* times 1024*1024*1024 */ break; case 'p': /* partition start */ case 'P': case 'l': /* partition length */ case 'L': errx(1, "%s: not supported yet %s", arg, msg); /* notreached */ } } return x; } /* * Check a volume label. */ static int oklabel(const char *src) { int c, i; for (i = 0; i <= 11; i++) { c = (u_char)*src++; if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c)) break; } return i && !c; } /* * Make a volume label. */ static void mklabel(u_int8_t *dest, const char *src) { int c, i; for (i = 0; i < 11; i++) { c = *src ? toupper(*src++) : ' '; *dest++ = !i && c == '\xe5' ? 5 : c; } } /* * Copy string, padding with spaces. */ static void setstr(u_int8_t *dest, const char *src, size_t len) { while (len--) *dest++ = *src ? *src++ : ' '; } /* * Print usage message. */ static void usage(void) { fprintf(stderr, "usage: newfs_msdos [ -options ] special [disktype]\n" "where the options are:\n" "\t-@ create file system at specified offset\n" "\t-B get bootstrap from file\n" "\t-C create image file with specified size\n" "\t-F FAT type (12, 16, or 32)\n" "\t-I volume ID\n" "\t-L volume label\n" "\t-N don't create file system: just print out parameters\n" "\t-O OEM string\n" "\t-S bytes/sector\n" "\t-a sectors/FAT\n" "\t-b block size\n" "\t-c sectors/cluster\n" "\t-e root directory entries\n" "\t-f standard format\n" "\t-h drive heads\n" "\t-i file system info sector\n" "\t-k backup boot sector\n" "\t-m media descriptor\n" "\t-n number of FATs\n" "\t-o hidden sectors\n" "\t-r reserved sectors\n" "\t-s file system size (sectors)\n" "\t-u sectors/track\n"); exit(1); } static void infohandler(int sig __unused) { got_siginfo = 1; } Index: head/share/man/man4/cd.4 =================================================================== --- head/share/man/man4/cd.4 (revision 276736) +++ head/share/man/man4/cd.4 (revision 276737) @@ -1,372 +1,362 @@ .\" Copyright (c) 1996 .\" Julian Elischer . All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd April 9, 2014 .Dt CD 4 .Os .Sh NAME .Nm cd .Nd SCSI CD-ROM driver .Sh SYNOPSIS .Cd device cd .Sh DESCRIPTION The .Nm driver provides support for a .Tn SCSI .Tn CD-ROM (Compact Disc-Read Only Memory) drive. In an attempt to look like a regular disk, the .Nm driver synthesizes a partition table, with one partition covering the entire .Tn CD-ROM . It is possible to modify this partition table using .Xr disklabel 8 , but it will only last until the .Tn CD-ROM is unmounted. In general the interfaces are similar to those described by .Xr ada 4 and .Xr da 4 . .Pp As the .Tn SCSI adapter is probed during boot, the .Tn SCSI bus is scanned for devices. Any devices found which answer as CDROM (type 5) or WORM (type 4) type devices will be `attached' to the .Nm driver. Prior to .Fx 2.1 , the first device found will be attached as .Li cd0 the next, .Li cd1 , etc. Beginning in .Fx 2.1 it is possible to specify what cd unit a device should come on line as; refer to .Xr scsi 4 for details on kernel configuration. .Pp The system utility .Xr disklabel 8 may be used to read the synthesized disk label structure, which will contain correct figures for the size of the .Tn CD-ROM should that information be required. .Sh KERNEL CONFIGURATION Any number of .Tn CD-ROM devices may be attached to the system regardless of system configuration as all resources are dynamically allocated. .Sh IOCTLS The following .Xr ioctl 2 calls which apply to .Tn SCSI .Tn CD-ROM drives are defined in the header files .In sys/cdio.h and .In sys/disklabel.h . .Bl -tag -width CDIOCREADSUBCHANNEL -.It Dv DIOCGDINFO -.It Dv DIOCSDINFO -.Pq Li "struct disklabel" -Read or write the in-core copy of the disklabel for the -drive. -The disklabel is initialized with information -read from the scsi inquiry commands, and should be the same as -the information printed at boot. -This structure is defined in the header file -.In sys/disklabel.h . .It Dv CDIOCPLAYTRACKS .Pq Li "struct ioc_play_track" Start audio playback given a track address and length. The structure is defined as follows: .Bd -literal -offset indent struct ioc_play_track { u_char start_track; u_char start_index; u_char end_track; u_char end_index; }; .Ed .It Dv CDIOCPLAYBLOCKS .Pq Li "struct ioc_play_blocks" Start audio playback given a block address and length. The structure is defined as follows: .Bd -literal -offset indent struct ioc_play_blocks { int blk; int len; }; .Ed .It Dv CDIOCPLAYMSF .Pq Li "struct ioc_play_msf" Start audio playback given a `minutes-seconds-frames' address and length. The structure is defined as follows: .Bd -literal -offset indent struct ioc_play_msf { u_char start_m; u_char start_s; u_char start_f; u_char end_m; u_char end_s; u_char end_f; }; .Ed .It Dv CDIOCREADSUBCHANNEL .Pq Li "struct ioc_read_subchannel" Read information from the subchannel at the location specified by this structure: .Bd -literal -offset indent struct ioc_read_subchannel { u_char address_format; #define CD_LBA_FORMAT 1 #define CD_MSF_FORMAT 2 u_char data_format; #define CD_SUBQ_DATA 0 #define CD_CURRENT_POSITION 1 #define CD_MEDIA_CATALOG 2 #define CD_TRACK_INFO 3 u_char track; int data_len; struct cd_sub_channel_info *data; }; .Ed .It Dv CDIOREADTOCHEADER .Pq Li "struct ioc_toc_header" Return summary information about the table of contents for the mounted .Tn CD-ROM . The information is returned into the following structure: .Bd -literal -offset indent struct ioc_toc_header { u_short len; u_char starting_track; u_char ending_track; }; .Ed .It Dv CDIOREADTOCENTRYS .Pq Li "struct ioc_read_toc_entry" Return information from the table of contents entries mentioned. .Pq Yes, this command name is misspelled. The argument structure is defined as follows: .Bd -literal -offset indent struct ioc_read_toc_entry { u_char address_format; u_char starting_track; u_short data_len; struct cd_toc_entry *data; }; .Ed The requested data is written into an area of size .Li data_len and pointed to by .Li data . .It Dv CDIOCSETPATCH .Pq Li "struct ioc_patch" Attach various audio channels to various output channels. The argument structure is defined thusly: .Bd -literal -offset indent struct ioc_patch { u_char patch[4]; /* one for each channel */ }; .Ed .It Dv CDIOCGETVOL .It Dv CDIOCSETVOL .Pq Li "struct ioc_vol" Get (set) information about the volume settings of the output channels. The argument structure is as follows: .Bd -literal -offset indent struct ioc_vol { u_char vol[4]; /* one for each channel */ }; .Ed .It Dv CDIOCSETMONO Patch all output channels to all source channels. .It Dv CDIOCSETSTEREO Patch left source channel to the left output channel and the right source channel to the right output channel. .It Dv CDIOCSETMUTE Mute output without changing the volume settings. .It Dv CDIOCSETLEFT .It Dv CDIOCSETRIGHT Attach both output channels to the left (right) source channel. .It Dv CDIOCSETDEBUG .It Dv CDIOCCLRDEBUG Turn on (off) debugging for the appropriate device. .It Dv CDIOCPAUSE .It Dv CDIOCRESUME Pause (resume) audio play, without resetting the location of the read-head. .It Dv CDIOCRESET Reset the drive. .It Dv CDIOCSTART .It Dv CDIOCSTOP Tell the drive to spin-up (-down) the .Tn CD-ROM . .It Dv CDIOCALLOW .It Dv CDIOCPREVENT Tell the drive to allow (prevent) manual ejection of the .Tn CD-ROM disc. Not all drives support this feature. .It Dv CDIOCEJECT Eject the .Tn CD-ROM . .It Dv CDIOCCLOSE Tell the drive to close its door and load the media. Not all drives support this feature. .El .Sh NOTES When a .Tn CD-ROM is changed in a drive controlled by the .Nm driver, then the act of changing the media will invalidate the disklabel and information held within the kernel. To stop corruption, all accesses to the device will be discarded until there are no more open file descriptors referencing the device. During this period, all new open attempts will be rejected. When no more open file descriptors reference the device, the first next open will load a new set of parameters (including disklabel) for the drive. .Pp The audio code in the .Nm driver only support .Tn SCSI-2 standard audio commands. As many .Tn CD-ROM manufacturers have not followed the standard, there are many .Tn CD-ROM drives for which audio will not work. Some work is planned to support some of the more common `broken' .Tn CD-ROM drives; however, this is not yet under way. .Sh SYSCTL VARIABLES The following variables are available as both .Xr sysctl 8 variables and .Xr loader 8 tunables: .Bl -tag -width 12 .It kern.cam.cd.retry_count .Pp This variable determines how many times the .Nm driver will retry a READ or WRITE command. This does not affect the number of retries used during probe time or for the .Nm driver dump routine. This value currently defaults to 4. .It kern.cam.cd.%d.minimum_cmd_size .Pp The .Nm driver attempts to automatically determine whether the drive it is talking to supports 6 byte or 10 byte MODE SENSE/MODE SELECT operations. Many .Tn SCSI drives only support 6 byte commands, and .Tn ATAPI drives only support 10 byte commands. The .Nm driver first attempts to determine whether the protocol in use typically supports 6 byte commands by issuing a CAM Path Inquiry CCB. It will then default to 6 byte or 10 byte commands as appropriate. After that, the .Nm driver defaults to using 6 byte commands (assuming the protocol the drive speaks claims to support 6 byte commands), until one fails with a .Tn SCSI ILLEGAL REQUEST error. Then it tries the 10 byte version of the command to see if that works instead. Users can change the default via per-drive sysctl variables and loader tunables. Where .Dq %d is the unit number of the drive in question. Valid minimum command sizes are 6 and 10. Any value above 6 will be rounded to 10, and any value below 6 will be rounded to 6. .El .Sh FILES .Bl -tag -width /dev/cd[0-9][a-h] -compact .It Pa /dev/cd[0-9][a-h] raw mode .Tn CD-ROM devices .El .Sh DIAGNOSTICS None. .Sh SEE ALSO .Xr cam 4 , .Xr da 4 , .Xr disklabel 8 , .Xr cd 9 .Sh HISTORY This .Nm driver is based upon the .Nm driver written by Julian Elischer, which appeared in .Bx 386 0.1 . The CAM version of the .Nm driver was written by Kenneth Merry and first appeared in .Fx 3.0 . .Sh BUGS The names of the structures used for the third argument to .Fn ioctl were poorly chosen, and a number of spelling errors have survived in the names of the .Fn ioctl commands. Index: head/share/man/man4/mcd.4 =================================================================== --- head/share/man/man4/mcd.4 (revision 276736) +++ head/share/man/man4/mcd.4 (revision 276737) @@ -1,169 +1,165 @@ .\" .\" Copyright (c) 1994 Keith E. Walker .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd December 8, 1994 .Dt MCD 4 .Os .Sh NAME .Nm mcd .Nd Mitsumi CD-ROM driver .Sh SYNOPSIS .Cd "device mcd" .Pp In .Pa /boot/device.hints : .Cd hint.mcd.0.at="isa" .Cd hint.mcd.0.port="0x300" .Cd hint.mcd.0.irq="10" .Sh DESCRIPTION The .Nm driver provides a data and audio interface to the Mitsumi-brand CD-ROM player. The CD-ROM player must be interfaced to the ISA bus through one of the Mitsumi proprietary controller boards. The controller boards supported are the LU002S, LU005S, the FX001 and the quite common FX001D. .Pp The .Nm driver responds to disk-specific .Fn ioctl commands, namely the -.Dv DIOCGDINFO , -.Dv DIOCGPART , -.Dv DIOCWDINFO , -and -.Dv DIOCSDINFO , -commands. +.Dv DIOCGPART +command. Other disk-specific .Fn ioctl commands will return an error. .Pp The .Nm driver also responds to special CD-ROM .Fn ioctl commands. These commands control the CD-ROM player's audio features. The commands are: .Pp .Bl -tag -width CDIOCREADSUBCHANNEL -compact -offset indent .It CDIOCREADSUBCHANNEL get sub-channel information on current status of disc playing .It CDIOCREADTOCHEADER get table of contents header .It CDIOCREADTOCENTRYS gets all of the table of contents .It CDIOCPLAYTRACKS begins audio playing at location specified .It CDIOCPLAYBLOCKS fails with error .Er EINVAL .It CDIOCPLAYMSF begins audio playing at location specified .It CDIOCRESUME resumes playing a previously paused disc .It CDIOCPAUSE pauses a playing disc .It CDIOCSTART begins playing a disc .It CDIOCSTOP stops a previously playing disc .It CDIOCEJECT opens the disc tray (there is no support for a corresponding un-eject command). .It CDIOCRESET stops any play and resets the Mitsumi controller board .It CDIOCSETDEBUG cause the kernel to print debug messages to the console about the .Nm driver .It CDIOCCLRDEBUG cause the kernel to quit printing debug messages about the .Nm driver .El .Pp The .Fn ioctl commands defined above are the only ones that the .Nm driver supports. There are other CD-ROM related .Fn ioctl commands (such as .Dv CDIOCSETVOL and .Dv CDIOCSETSTERIO ) which are available and may be supported by future versions of the driver. .Sh FILES .Bl -tag -width /dev/(r)mcd0a -compact .It Pa /dev/(r)mcd0a accesses .Bx partition on the disc. Normally, there is only one file system on a CD-ROM disc. .It Pa /dev/(r)mcd0c accesses raw device. .El .Sh NOTES The character-mode devices for the .Nm driver should only be used for accessing the audio features of the CD-ROM player as the performance on data is abysmal. .Pp The current version of the driver uses neither the DMA or IRQ features of the interface board, although it has an interrupt handler for any IRQ requests that are generated. Until the DMA features are supported, the only interrupts that the board generates are those that are not supported by the driver anyway. .Sh SEE ALSO .In sys/cdio.h .Sh HISTORY An .Nm driver appeared in .Fx 1.0 . .Sh AUTHORS .An -nosplit The driver was written by .An Holger Veit (data part) and .An Brian Moore (audio part). Changes were provided by .An Gary Clark II , .An Andrew A. Chernov , and .An Jordan K. Hubbard . Index: head/sys/geom/geom_bsd.c =================================================================== --- head/sys/geom/geom_bsd.c (revision 276736) +++ head/sys/geom/geom_bsd.c (revision 276737) @@ -1,704 +1,616 @@ /*- * Copyright (c) 2002 Poul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the * DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * This is the method for dealing with BSD disklabels. It has been * extensively (by my standards at least) commented, in the vain hope that * it will serve as the source in future copy&paste operations. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include FEATURE(geom_bsd, "GEOM BSD disklabels support"); #define BSD_CLASS_NAME "BSD" #define ALPHA_LABEL_OFFSET 64 #define HISTORIC_LABEL_OFFSET 512 #define LABELSIZE (148 + 16 * MAXPARTITIONS) static void g_bsd_hotwrite(void *arg, int flag); /* * Our private data about one instance. All the rest is handled by the * slice code and stored in its softc, so this is just the stuff * specific to BSD disklabels. */ struct g_bsd_softc { off_t labeloffset; off_t mbroffset; off_t rawoffset; struct disklabel ondisk; u_char label[LABELSIZE]; u_char labelsum[16]; }; /* * Modify our slicer to match proposed disklabel, if possible. * This is where we make sure we don't do something stupid. */ static int g_bsd_modify(struct g_geom *gp, u_char *label) { int i, error; struct partition *ppp; struct g_slicer *gsp; struct g_consumer *cp; struct g_bsd_softc *ms; u_int secsize, u; off_t rawoffset, o; struct disklabel dl; MD5_CTX md5sum; g_topology_assert(); gsp = gp->softc; ms = gsp->softc; error = bsd_disklabel_le_dec(label, &dl, MAXPARTITIONS); if (error) { return (error); } /* Get dimensions of our device. */ cp = LIST_FIRST(&gp->consumer); secsize = cp->provider->sectorsize; /* ... or a smaller sector size. */ if (dl.d_secsize < secsize) { return (EINVAL); } /* ... or a non-multiple sector size. */ if (dl.d_secsize % secsize != 0) { return (EINVAL); } /* Historical braindamage... */ rawoffset = (off_t)dl.d_partitions[RAW_PART].p_offset * dl.d_secsize; for (i = 0; i < dl.d_npartitions; i++) { ppp = &dl.d_partitions[i]; if (ppp->p_size == 0) continue; o = (off_t)ppp->p_offset * dl.d_secsize; if (o < rawoffset) rawoffset = 0; } if (rawoffset != 0 && (off_t)rawoffset != ms->mbroffset) printf("WARNING: %s expected rawoffset %jd, found %jd\n", gp->name, (intmax_t)ms->mbroffset/dl.d_secsize, (intmax_t)rawoffset/dl.d_secsize); /* Don't munge open partitions. */ for (i = 0; i < dl.d_npartitions; i++) { ppp = &dl.d_partitions[i]; o = (off_t)ppp->p_offset * dl.d_secsize; if (o == 0) o = rawoffset; error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, o - rawoffset, (off_t)ppp->p_size * dl.d_secsize, dl.d_secsize, "%s%c", gp->name, 'a' + i); if (error) return (error); } /* Look good, go for it... */ for (u = 0; u < gsp->nslice; u++) { ppp = &dl.d_partitions[u]; o = (off_t)ppp->p_offset * dl.d_secsize; if (o == 0) o = rawoffset; g_slice_config(gp, u, G_SLICE_CONFIG_SET, o - rawoffset, (off_t)ppp->p_size * dl.d_secsize, dl.d_secsize, "%s%c", gp->name, 'a' + u); } /* Update our softc */ ms->ondisk = dl; if (label != ms->label) bcopy(label, ms->label, LABELSIZE); ms->rawoffset = rawoffset; /* * In order to avoid recursively attaching to the same * on-disk label (it's usually visible through the 'c' * partition) we calculate an MD5 and ask if other BSD's * below us love that label. If they do, we don't. */ MD5Init(&md5sum); MD5Update(&md5sum, ms->label, sizeof(ms->label)); MD5Final(ms->labelsum, &md5sum); return (0); } /* * This is an internal helper function, called multiple times from the taste * function to try to locate a disklabel on the disk. More civilized formats * will not need this, as there is only one possible place on disk to look * for the magic spot. */ static int g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset) { int error; u_char *buf; struct disklabel *dl; off_t secoff; /* * We need to read entire aligned sectors, and we assume that the * disklabel does not span sectors, so one sector is enough. */ secoff = offset % secsize; buf = g_read_data(cp, offset - secoff, secsize, NULL); if (buf == NULL) return (ENOENT); /* Decode into our native format. */ dl = &ms->ondisk; error = bsd_disklabel_le_dec(buf + secoff, dl, MAXPARTITIONS); if (!error) bcopy(buf + secoff, ms->label, LABELSIZE); /* Remember to free the buffer g_read_data() gave us. */ g_free(buf); ms->labeloffset = offset; return (error); } /* * This function writes the current label to disk, possibly updating * the alpha SRM checksum. */ static int g_bsd_writelabel(struct g_geom *gp, u_char *bootcode) { off_t secoff; u_int secsize; struct g_consumer *cp; struct g_slicer *gsp; struct g_bsd_softc *ms; u_char *buf; uint64_t sum; int error, i; gsp = gp->softc; ms = gsp->softc; cp = LIST_FIRST(&gp->consumer); /* Get sector size, we need it to read data. */ secsize = cp->provider->sectorsize; secoff = ms->labeloffset % secsize; if (bootcode == NULL) { buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error); if (buf == NULL) return (error); bcopy(ms->label, buf + secoff, sizeof(ms->label)); } else { buf = bootcode; bcopy(ms->label, buf + ms->labeloffset, sizeof(ms->label)); } if (ms->labeloffset == ALPHA_LABEL_OFFSET) { sum = 0; for (i = 0; i < 63; i++) sum += le64dec(buf + i * 8); le64enc(buf + 504, sum); } if (bootcode == NULL) { error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize); g_free(buf); } else { error = g_write_data(cp, 0, bootcode, BBSIZE); } return(error); } /* * If the user tries to overwrite our disklabel through an open partition * or via a magicwrite config call, we end up here and try to prevent * footshooting as best we can. */ static void g_bsd_hotwrite(void *arg, int flag) { struct bio *bp; struct g_geom *gp; struct g_slicer *gsp; struct g_slice *gsl; struct g_bsd_softc *ms; u_char *p; int error; g_topology_assert(); /* * We should never get canceled, because that would amount to a removal * of the geom while there was outstanding I/O requests. */ KASSERT(flag != EV_CANCEL, ("g_bsd_hotwrite cancelled")); bp = arg; gp = bp->bio_to->geom; gsp = gp->softc; ms = gsp->softc; gsl = &gsp->slices[bp->bio_to->index]; - p = (u_char*)bp->bio_data + ms->labeloffset - - (bp->bio_offset + gsl->offset); + p = (u_char*)bp->bio_data + ms->labeloffset - + (bp->bio_offset + gsl->offset); error = g_bsd_modify(gp, p); if (error) { g_io_deliver(bp, EPERM); return; } g_slice_finish_hot(bp); } -/*- - * This start routine is only called for non-trivial requests, all the - * trivial ones are handled autonomously by the slice code. - * For requests we handle here, we must call the g_io_deliver() on the - * bio, and return non-zero to indicate to the slice code that we did so. - * This code executes in the "DOWN" I/O path, this means: - * * No sleeping. - * * Don't grab the topology lock. - * * Don't call biowait, g_getattr(), g_setattr() or g_read_data() - */ static int -g_bsd_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) -{ - struct g_geom *gp; - struct g_bsd_softc *ms; - struct g_slicer *gsp; - u_char *label; - int error; - - gp = pp->geom; - gsp = gp->softc; - ms = gsp->softc; - - switch(cmd) { - case DIOCGDINFO: - /* Return a copy of the disklabel to userland. */ - bsd_disklabel_le_dec(ms->label, data, MAXPARTITIONS); - return(0); - case DIOCBSDBB: { - struct g_consumer *cp; - u_char *buf; - void *p; - int error, i; - uint64_t sum; - - if (!(fflag & FWRITE)) - return (EPERM); - /* The disklabel to set is the ioctl argument. */ - buf = g_malloc(BBSIZE, M_WAITOK); - p = *(void **)data; - error = copyin(p, buf, BBSIZE); - if (!error) { - /* XXX: Rude, but supposedly safe */ - DROP_GIANT(); - g_topology_lock(); - /* Validate and modify our slice instance to match. */ - error = g_bsd_modify(gp, buf + ms->labeloffset); - if (!error) { - cp = LIST_FIRST(&gp->consumer); - if (ms->labeloffset == ALPHA_LABEL_OFFSET) { - sum = 0; - for (i = 0; i < 63; i++) - sum += le64dec(buf + i * 8); - le64enc(buf + 504, sum); - } - error = g_write_data(cp, 0, buf, BBSIZE); - } - g_topology_unlock(); - PICKUP_GIANT(); - } - g_free(buf); - return (error); - } - case DIOCSDINFO: - case DIOCWDINFO: { - if (!(fflag & FWRITE)) - return (EPERM); - label = g_malloc(LABELSIZE, M_WAITOK); - /* The disklabel to set is the ioctl argument. */ - bsd_disklabel_le_enc(label, data); - - DROP_GIANT(); - g_topology_lock(); - /* Validate and modify our slice instance to match. */ - error = g_bsd_modify(gp, label); - if (error == 0 && cmd == DIOCWDINFO) - error = g_bsd_writelabel(gp, NULL); - g_topology_unlock(); - PICKUP_GIANT(); - g_free(label); - return(error); - } - default: - return (ENOIOCTL); - } -} - -static int g_bsd_start(struct bio *bp) { struct g_geom *gp; struct g_bsd_softc *ms; struct g_slicer *gsp; gp = bp->bio_to->geom; gsp = gp->softc; ms = gsp->softc; if (bp->bio_cmd == BIO_GETATTR) { if (g_handleattr(bp, "BSD::labelsum", ms->labelsum, sizeof(ms->labelsum))) return (1); } return (0); } /* * Dump configuration information in XML format. * Notice that the function is called once for the geom and once for each * consumer and provider. We let g_slice_dumpconf() do most of the work. */ static void g_bsd_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp) { struct g_bsd_softc *ms; struct g_slicer *gsp; gsp = gp->softc; ms = gsp->softc; g_slice_dumpconf(sb, indent, gp, cp, pp); if (indent != NULL && pp == NULL && cp == NULL) { sbuf_printf(sb, "%s%jd\n", indent, (intmax_t)ms->labeloffset); sbuf_printf(sb, "%s%jd\n", indent, (intmax_t)ms->rawoffset); sbuf_printf(sb, "%s%jd\n", indent, (intmax_t)ms->mbroffset); } else if (pp != NULL) { if (indent == NULL) sbuf_printf(sb, " ty %d", ms->ondisk.d_partitions[pp->index].p_fstype); else sbuf_printf(sb, "%s%d\n", indent, ms->ondisk.d_partitions[pp->index].p_fstype); } } /* * The taste function is called from the event-handler, with the topology * lock already held and a provider to examine. The flags are unused. * * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and * if we find valid, consistent magic on it, build a geom on it. * * There may be cases where the operator would like to put a BSD-geom on * providers which do not meet all of the requirements. This can be done * by instead passing the G_TF_INSIST flag, which will override these * checks. * * The final flags value is G_TF_TRANSPARENT, which instructs the method * to put a geom on top of the provider and configure it to be as transparent * as possible. This is not really relevant to the BSD method and therefore * not implemented here. */ static struct uuid freebsd_slice = GPT_ENT_TYPE_FREEBSD; static struct g_geom * g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags) { struct g_geom *gp; struct g_consumer *cp; int error, i; struct g_bsd_softc *ms; u_int secsize; struct g_slicer *gsp; u_char hash[16]; MD5_CTX md5sum; struct uuid uuid; g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name); g_topology_assert(); /* We don't implement transparent inserts. */ if (flags == G_TF_TRANSPARENT) return (NULL); /* * BSD labels are a subclass of the general "slicing" topology so * a lot of the work can be done by the common "slice" code. * Create a geom with space for MAXPARTITIONS providers, one consumer * and a softc structure for us. Specify the provider to attach * the consumer to and our "start" routine for special requests. * The provider is opened with mode (1,0,0) so we can do reads * from it. */ gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms, sizeof(*ms), g_bsd_start); if (gp == NULL) return (NULL); /* Get the geom_slicer softc from the geom. */ gsp = gp->softc; /* * The do...while loop here allows us to have multiple escapes * using a simple "break". This improves code clarity without * ending up in deep nesting and without using goto or come from. */ do { /* * If the provider is an MBR we will only auto attach * to type 165 slices in the G_TF_NORMAL case. We will * attach to any other type. */ error = g_getattr("MBR::type", cp, &i); if (!error) { if (i != 165 && flags == G_TF_NORMAL) break; error = g_getattr("MBR::offset", cp, &ms->mbroffset); if (error) break; } /* Same thing if we are inside a PC98 */ error = g_getattr("PC98::type", cp, &i); if (!error) { if (i != 0xc494 && flags == G_TF_NORMAL) break; error = g_getattr("PC98::offset", cp, &ms->mbroffset); if (error) break; } /* Same thing if we are inside a GPT */ error = g_getattr("GPT::type", cp, &uuid); if (!error) { if (memcmp(&uuid, &freebsd_slice, sizeof(uuid)) != 0 && flags == G_TF_NORMAL) break; } /* Get sector size, we need it to read data. */ secsize = cp->provider->sectorsize; if (secsize < 512) break; /* First look for a label at the start of the second sector. */ error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize); /* * If sector size is not 512 the label still can be at * offset 512, not at the start of the second sector. At least * it's true for labels created by the FreeBSD's bsdlabel(8). */ if (error && secsize != HISTORIC_LABEL_OFFSET) error = g_bsd_try(gp, gsp, cp, secsize, ms, HISTORIC_LABEL_OFFSET); /* Next, look for alpha labels */ if (error) error = g_bsd_try(gp, gsp, cp, secsize, ms, ALPHA_LABEL_OFFSET); /* If we didn't find a label, punt. */ if (error) break; /* * In order to avoid recursively attaching to the same * on-disk label (it's usually visible through the 'c' * partition) we calculate an MD5 and ask if other BSD's * below us love that label. If they do, we don't. */ MD5Init(&md5sum); MD5Update(&md5sum, ms->label, sizeof(ms->label)); MD5Final(ms->labelsum, &md5sum); error = g_getattr("BSD::labelsum", cp, &hash); if (!error && !bcmp(ms->labelsum, hash, sizeof(hash))) break; /* * Process the found disklabel, and modify our "slice" * instance to match it, if possible. */ error = g_bsd_modify(gp, ms->label); } while (0); /* Success or failure, we can close our provider now. */ g_access(cp, -1, 0, 0); /* If we have configured any providers, return the new geom. */ if (gsp->nprovider > 0) { g_slice_conf_hot(gp, 0, ms->labeloffset, LABELSIZE, G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL); gsp->hot = g_bsd_hotwrite; return (gp); } /* * ...else push the "self-destruct" button, by spoiling our own * consumer. This triggers a call to g_slice_spoiled which will * dismantle what was setup. */ g_slice_spoiled(cp); return (NULL); } struct h0h0 { struct g_geom *gp; struct g_bsd_softc *ms; u_char *label; int error; }; static void g_bsd_callconfig(void *arg, int flag) { struct h0h0 *hp; hp = arg; hp->error = g_bsd_modify(hp->gp, hp->label); if (!hp->error) hp->error = g_bsd_writelabel(hp->gp, NULL); } /* * NB! curthread is user process which GCTL'ed. */ static void g_bsd_config(struct gctl_req *req, struct g_class *mp, char const *verb) { u_char *label; int error; struct h0h0 h0h0; struct g_geom *gp; struct g_slicer *gsp; struct g_consumer *cp; struct g_bsd_softc *ms; g_topology_assert(); gp = gctl_get_geom(req, mp, "geom"); if (gp == NULL) return; cp = LIST_FIRST(&gp->consumer); gsp = gp->softc; ms = gsp->softc; if (!strcmp(verb, "read mbroffset")) { gctl_set_param_err(req, "mbroffset", &ms->mbroffset, sizeof(ms->mbroffset)); return; } else if (!strcmp(verb, "write label")) { label = gctl_get_paraml(req, "label", LABELSIZE); if (label == NULL) return; h0h0.gp = gp; h0h0.ms = gsp->softc; h0h0.label = label; h0h0.error = -1; /* XXX: Does this reference register with our selfdestruct code ? */ error = g_access(cp, 1, 1, 1); if (error) { gctl_error(req, "could not access consumer"); return; } g_bsd_callconfig(&h0h0, 0); error = h0h0.error; g_access(cp, -1, -1, -1); } else if (!strcmp(verb, "write bootcode")) { label = gctl_get_paraml(req, "bootcode", BBSIZE); if (label == NULL) return; /* XXX: Does this reference register with our selfdestruct code ? */ error = g_access(cp, 1, 1, 1); if (error) { gctl_error(req, "could not access consumer"); return; } error = g_bsd_writelabel(gp, label); g_access(cp, -1, -1, -1); } else { gctl_error(req, "Unknown verb parameter"); } return; } /* Finally, register with GEOM infrastructure. */ static struct g_class g_bsd_class = { .name = BSD_CLASS_NAME, .version = G_VERSION, .taste = g_bsd_taste, .ctlreq = g_bsd_config, .dumpconf = g_bsd_dumpconf, - .ioctl = g_bsd_ioctl, }; DECLARE_GEOM_CLASS(g_bsd_class, g_bsd); Index: head/sys/geom/part/g_part_bsd.c =================================================================== --- head/sys/geom/part/g_part_bsd.c (revision 276736) +++ head/sys/geom/part/g_part_bsd.c (revision 276737) @@ -1,575 +1,540 @@ /*- * Copyright (c) 2007 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "g_part_if.h" #define BOOT1_SIZE 512 #define LABEL_SIZE 512 #define BOOT2_OFF (BOOT1_SIZE + LABEL_SIZE) #define BOOT2_SIZE (BBSIZE - BOOT2_OFF) FEATURE(geom_part_bsd, "GEOM partitioning class for BSD disklabels"); struct g_part_bsd_table { struct g_part_table base; u_char *bbarea; uint32_t offset; }; struct g_part_bsd_entry { struct g_part_entry base; struct partition part; }; static int g_part_bsd_add(struct g_part_table *, struct g_part_entry *, struct g_part_parms *); static int g_part_bsd_bootcode(struct g_part_table *, struct g_part_parms *); static int g_part_bsd_create(struct g_part_table *, struct g_part_parms *); static int g_part_bsd_destroy(struct g_part_table *, struct g_part_parms *); static void g_part_bsd_dumpconf(struct g_part_table *, struct g_part_entry *, struct sbuf *, const char *); static int g_part_bsd_dumpto(struct g_part_table *, struct g_part_entry *); static int g_part_bsd_modify(struct g_part_table *, struct g_part_entry *, struct g_part_parms *); static const char *g_part_bsd_name(struct g_part_table *, struct g_part_entry *, char *, size_t); static int g_part_bsd_probe(struct g_part_table *, struct g_consumer *); static int g_part_bsd_read(struct g_part_table *, struct g_consumer *); static const char *g_part_bsd_type(struct g_part_table *, struct g_part_entry *, char *, size_t); static int g_part_bsd_write(struct g_part_table *, struct g_consumer *); static int g_part_bsd_resize(struct g_part_table *, struct g_part_entry *, struct g_part_parms *); -static int g_part_bsd_ioctl(struct g_part_table *, struct g_provider *, - u_long cmd, void *data, int fflag, struct thread *td); static kobj_method_t g_part_bsd_methods[] = { KOBJMETHOD(g_part_add, g_part_bsd_add), KOBJMETHOD(g_part_bootcode, g_part_bsd_bootcode), KOBJMETHOD(g_part_create, g_part_bsd_create), KOBJMETHOD(g_part_destroy, g_part_bsd_destroy), KOBJMETHOD(g_part_dumpconf, g_part_bsd_dumpconf), KOBJMETHOD(g_part_dumpto, g_part_bsd_dumpto), KOBJMETHOD(g_part_modify, g_part_bsd_modify), KOBJMETHOD(g_part_resize, g_part_bsd_resize), KOBJMETHOD(g_part_name, g_part_bsd_name), KOBJMETHOD(g_part_probe, g_part_bsd_probe), KOBJMETHOD(g_part_read, g_part_bsd_read), KOBJMETHOD(g_part_type, g_part_bsd_type), KOBJMETHOD(g_part_write, g_part_bsd_write), - KOBJMETHOD(g_part_ioctl, g_part_bsd_ioctl), { 0, 0 } }; static struct g_part_scheme g_part_bsd_scheme = { "BSD", g_part_bsd_methods, sizeof(struct g_part_bsd_table), .gps_entrysz = sizeof(struct g_part_bsd_entry), .gps_minent = 8, .gps_maxent = 20, /* Only 22 entries fit in 512 byte sectors */ .gps_bootcodesz = BBSIZE, }; G_PART_SCHEME_DECLARE(g_part_bsd); static struct g_part_bsd_alias { uint8_t type; int alias; } bsd_alias_match[] = { { FS_BSDFFS, G_PART_ALIAS_FREEBSD_UFS }, { FS_SWAP, G_PART_ALIAS_FREEBSD_SWAP }, { FS_ZFS, G_PART_ALIAS_FREEBSD_ZFS }, { FS_VINUM, G_PART_ALIAS_FREEBSD_VINUM }, { FS_NANDFS, G_PART_ALIAS_FREEBSD_NANDFS }, { FS_HAMMER, G_PART_ALIAS_DFBSD_HAMMER }, { FS_HAMMER2, G_PART_ALIAS_DFBSD_HAMMER2 }, }; static int bsd_parse_type(const char *type, uint8_t *fstype) { const char *alias; char *endp; long lt; int i; if (type[0] == '!') { lt = strtol(type + 1, &endp, 0); if (type[1] == '\0' || *endp != '\0' || lt <= 0 || lt >= 256) return (EINVAL); *fstype = (u_int)lt; return (0); } for (i = 0; i < sizeof(bsd_alias_match) / sizeof(bsd_alias_match[0]); i++) { alias = g_part_alias_name(bsd_alias_match[i].alias); if (strcasecmp(type, alias) == 0) { *fstype = bsd_alias_match[i].type; return (0); } } return (EINVAL); } static int g_part_bsd_add(struct g_part_table *basetable, struct g_part_entry *baseentry, struct g_part_parms *gpp) { struct g_part_bsd_entry *entry; struct g_part_bsd_table *table; if (gpp->gpp_parms & G_PART_PARM_LABEL) return (EINVAL); entry = (struct g_part_bsd_entry *)baseentry; table = (struct g_part_bsd_table *)basetable; entry->part.p_size = gpp->gpp_size; entry->part.p_offset = gpp->gpp_start + table->offset; entry->part.p_fsize = 0; entry->part.p_frag = 0; entry->part.p_cpg = 0; return (bsd_parse_type(gpp->gpp_type, &entry->part.p_fstype)); } static int g_part_bsd_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) { struct g_part_bsd_table *table; const u_char *codeptr; if (gpp->gpp_codesize != BOOT1_SIZE && gpp->gpp_codesize != BBSIZE) return (ENODEV); table = (struct g_part_bsd_table *)basetable; codeptr = gpp->gpp_codeptr; bcopy(codeptr, table->bbarea, BOOT1_SIZE); if (gpp->gpp_codesize == BBSIZE) bcopy(codeptr + BOOT2_OFF, table->bbarea + BOOT2_OFF, BOOT2_SIZE); return (0); } static int g_part_bsd_create(struct g_part_table *basetable, struct g_part_parms *gpp) { struct g_provider *pp; struct g_part_entry *baseentry; struct g_part_bsd_entry *entry; struct g_part_bsd_table *table; u_char *ptr; uint32_t msize, ncyls, secpercyl; pp = gpp->gpp_provider; if (pp->sectorsize < sizeof(struct disklabel)) return (ENOSPC); if (BBSIZE % pp->sectorsize) return (ENOTBLK); msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); secpercyl = basetable->gpt_sectors * basetable->gpt_heads; ncyls = msize / secpercyl; table = (struct g_part_bsd_table *)basetable; table->bbarea = g_malloc(BBSIZE, M_WAITOK | M_ZERO); ptr = table->bbarea + pp->sectorsize; le32enc(ptr + 0, DISKMAGIC); /* d_magic */ le32enc(ptr + 40, pp->sectorsize); /* d_secsize */ le32enc(ptr + 44, basetable->gpt_sectors); /* d_nsectors */ le32enc(ptr + 48, basetable->gpt_heads); /* d_ntracks */ le32enc(ptr + 52, ncyls); /* d_ncylinders */ le32enc(ptr + 56, secpercyl); /* d_secpercyl */ le32enc(ptr + 60, msize); /* d_secperunit */ le16enc(ptr + 72, 3600); /* d_rpm */ le32enc(ptr + 132, DISKMAGIC); /* d_magic2 */ le16enc(ptr + 138, basetable->gpt_entries); /* d_npartitions */ le32enc(ptr + 140, BBSIZE); /* d_bbsize */ basetable->gpt_first = 0; basetable->gpt_last = msize - 1; basetable->gpt_isleaf = 1; baseentry = g_part_new_entry(basetable, RAW_PART + 1, basetable->gpt_first, basetable->gpt_last); baseentry->gpe_internal = 1; entry = (struct g_part_bsd_entry *)baseentry; entry->part.p_size = basetable->gpt_last + 1; entry->part.p_offset = table->offset; return (0); } static int g_part_bsd_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) { struct g_part_bsd_table *table; table = (struct g_part_bsd_table *)basetable; if (table->bbarea != NULL) g_free(table->bbarea); table->bbarea = NULL; /* Wipe the second sector to clear the partitioning. */ basetable->gpt_smhead |= 2; return (0); } static void g_part_bsd_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, struct sbuf *sb, const char *indent) { struct g_part_bsd_entry *entry; entry = (struct g_part_bsd_entry *)baseentry; if (indent == NULL) { /* conftxt: libdisk compatibility */ sbuf_printf(sb, " xs BSD xt %u", entry->part.p_fstype); } else if (entry != NULL) { /* confxml: partition entry information */ sbuf_printf(sb, "%s%u\n", indent, entry->part.p_fstype); } else { /* confxml: scheme information */ } } static int g_part_bsd_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) { struct g_part_bsd_entry *entry; /* Allow dumping to a swap partition or an unused partition. */ entry = (struct g_part_bsd_entry *)baseentry; return ((entry->part.p_fstype == FS_UNUSED || entry->part.p_fstype == FS_SWAP) ? 1 : 0); } static int g_part_bsd_modify(struct g_part_table *basetable, struct g_part_entry *baseentry, struct g_part_parms *gpp) { struct g_part_bsd_entry *entry; if (gpp->gpp_parms & G_PART_PARM_LABEL) return (EINVAL); entry = (struct g_part_bsd_entry *)baseentry; if (gpp->gpp_parms & G_PART_PARM_TYPE) return (bsd_parse_type(gpp->gpp_type, &entry->part.p_fstype)); return (0); } static void bsd_set_rawsize(struct g_part_table *basetable, struct g_provider *pp) { struct g_part_bsd_table *table; struct g_part_bsd_entry *entry; struct g_part_entry *baseentry; uint32_t msize; table = (struct g_part_bsd_table *)basetable; msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); le32enc(table->bbarea + pp->sectorsize + 60, msize); /* d_secperunit */ basetable->gpt_last = msize - 1; LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) { if (baseentry->gpe_index != RAW_PART + 1) continue; baseentry->gpe_end = basetable->gpt_last; entry = (struct g_part_bsd_entry *)baseentry; entry->part.p_size = msize; return; } } static int g_part_bsd_resize(struct g_part_table *basetable, struct g_part_entry *baseentry, struct g_part_parms *gpp) { struct g_part_bsd_entry *entry; struct g_provider *pp; if (baseentry == NULL) { pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; bsd_set_rawsize(basetable, pp); return (0); } entry = (struct g_part_bsd_entry *)baseentry; baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; entry->part.p_size = gpp->gpp_size; return (0); } static const char * g_part_bsd_name(struct g_part_table *table, struct g_part_entry *baseentry, char *buf, size_t bufsz) { snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1); return (buf); } static int g_part_bsd_probe(struct g_part_table *table, struct g_consumer *cp) { struct g_provider *pp; u_char *buf; uint32_t magic1, magic2; int error; pp = cp->provider; /* Sanity-check the provider. */ if (pp->sectorsize < sizeof(struct disklabel) || pp->mediasize < BBSIZE) return (ENOSPC); if (BBSIZE % pp->sectorsize) return (ENOTBLK); /* Check that there's a disklabel. */ buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error); if (buf == NULL) return (error); magic1 = le32dec(buf + 0); magic2 = le32dec(buf + 132); g_free(buf); return ((magic1 == DISKMAGIC && magic2 == DISKMAGIC) ? G_PART_PROBE_PRI_HIGH : ENXIO); } static int g_part_bsd_read(struct g_part_table *basetable, struct g_consumer *cp) { struct g_provider *pp; struct g_part_bsd_table *table; struct g_part_entry *baseentry; struct g_part_bsd_entry *entry; struct partition part; u_char *buf, *p; off_t chs, msize; u_int sectors, heads; int error, index; pp = cp->provider; table = (struct g_part_bsd_table *)basetable; msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); table->bbarea = g_read_data(cp, 0, BBSIZE, &error); if (table->bbarea == NULL) return (error); buf = table->bbarea + pp->sectorsize; if (le32dec(buf + 40) != pp->sectorsize) goto invalid_label; sectors = le32dec(buf + 44); if (sectors < 1 || sectors > 255) goto invalid_label; if (sectors != basetable->gpt_sectors && !basetable->gpt_fixgeom) { g_part_geometry_heads(msize, sectors, &chs, &heads); if (chs != 0) { basetable->gpt_sectors = sectors; basetable->gpt_heads = heads; } } heads = le32dec(buf + 48); if (heads < 1 || heads > 255) goto invalid_label; if (heads != basetable->gpt_heads && !basetable->gpt_fixgeom) basetable->gpt_heads = heads; chs = le32dec(buf + 60); if (chs < 1) goto invalid_label; /* Fix-up a sysinstall bug. */ if (chs > msize) { chs = msize; le32enc(buf + 60, msize); } basetable->gpt_first = 0; basetable->gpt_last = msize - 1; basetable->gpt_isleaf = 1; basetable->gpt_entries = le16dec(buf + 138); if (basetable->gpt_entries < g_part_bsd_scheme.gps_minent || basetable->gpt_entries > g_part_bsd_scheme.gps_maxent) goto invalid_label; table->offset = le32dec(buf + 148 + RAW_PART * 16 + 4); for (index = basetable->gpt_entries - 1; index >= 0; index--) { p = buf + 148 + index * 16; part.p_size = le32dec(p + 0); part.p_offset = le32dec(p + 4); part.p_fsize = le32dec(p + 8); part.p_fstype = p[12]; part.p_frag = p[13]; part.p_cpg = le16dec(p + 14); if (part.p_size == 0) continue; if (part.p_offset < table->offset) continue; if (part.p_offset - table->offset > basetable->gpt_last) goto invalid_label; baseentry = g_part_new_entry(basetable, index + 1, part.p_offset - table->offset, part.p_offset - table->offset + part.p_size - 1); entry = (struct g_part_bsd_entry *)baseentry; entry->part = part; if (index == RAW_PART) baseentry->gpe_internal = 1; } return (0); invalid_label: printf("GEOM: %s: invalid disklabel.\n", pp->name); g_free(table->bbarea); table->bbarea = NULL; return (EINVAL); } static const char * g_part_bsd_type(struct g_part_table *basetable, struct g_part_entry *baseentry, char *buf, size_t bufsz) { struct g_part_bsd_entry *entry; int type; entry = (struct g_part_bsd_entry *)baseentry; type = entry->part.p_fstype; if (type == FS_NANDFS) return (g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS)); if (type == FS_SWAP) return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP)); if (type == FS_BSDFFS) return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS)); if (type == FS_VINUM) return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM)); if (type == FS_ZFS) return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS)); snprintf(buf, bufsz, "!%d", type); return (buf); -} - -/*- - * This start routine is only called for non-trivial requests, all the - * trivial ones are handled autonomously by the slice code. - * For requests we handle here, we must call the g_io_deliver() on the - * bio, and return non-zero to indicate to the slice code that we did so. - * This code executes in the "DOWN" I/O path, this means: - * * No sleeping. - * * Don't grab the topology lock. - * * Don't call biowait, g_getattr(), g_setattr() or g_read_data() - */ -static int -g_part_bsd_ioctl(struct g_part_table *basetable, struct g_provider *pp, - u_long cmd, void *data, int fflag, struct thread *td) -{ - - switch (cmd) - { - case DIOCGDINFO: - { - struct g_part_bsd_table *table; - u_char *p; - - table = (struct g_part_bsd_table *)basetable; - p = table->bbarea + pp->sectorsize; - return (bsd_disklabel_le_dec(p, data, MAXPARTITIONS)); - } - default: - return (ENOIOCTL); - - } } static int g_part_bsd_write(struct g_part_table *basetable, struct g_consumer *cp) { struct g_provider *pp; struct g_part_entry *baseentry; struct g_part_bsd_entry *entry; struct g_part_bsd_table *table; uint16_t sum; u_char *label, *p, *pe; int error, index; pp = cp->provider; table = (struct g_part_bsd_table *)basetable; baseentry = LIST_FIRST(&basetable->gpt_entry); label = table->bbarea + pp->sectorsize; for (index = 1; index <= basetable->gpt_entries; index++) { p = label + 148 + (index - 1) * 16; entry = (baseentry != NULL && index == baseentry->gpe_index) ? (struct g_part_bsd_entry *)baseentry : NULL; if (entry != NULL && !baseentry->gpe_deleted) { le32enc(p + 0, entry->part.p_size); le32enc(p + 4, entry->part.p_offset); le32enc(p + 8, entry->part.p_fsize); p[12] = entry->part.p_fstype; p[13] = entry->part.p_frag; le16enc(p + 14, entry->part.p_cpg); } else bzero(p, 16); if (entry != NULL) baseentry = LIST_NEXT(baseentry, gpe_entry); } /* Calculate checksum. */ le16enc(label + 136, 0); pe = label + 148 + basetable->gpt_entries * 16; sum = 0; for (p = label; p < pe; p += 2) sum ^= le16dec(p); le16enc(label + 136, sum); error = g_write_data(cp, 0, table->bbarea, BBSIZE); return (error); } Index: head/sys/sys/disklabel.h =================================================================== --- head/sys/sys/disklabel.h (revision 276736) +++ head/sys/sys/disklabel.h (revision 276737) @@ -1,312 +1,305 @@ /*- * Copyright (c) 1987, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)disklabel.h 8.2 (Berkeley) 7/10/94 * $FreeBSD$ */ #ifndef _SYS_DISKLABEL_H_ #define _SYS_DISKLABEL_H_ #ifndef _KERNEL #include #endif #include /* * Disk description table, see disktab(5) */ #define _PATH_DISKTAB "/etc/disktab" /* * Each disk has a label which includes information about the hardware * disk geometry, filesystem partitions, and drive specific information. * The label is in block 0 or 1, possibly offset from the beginning * to leave room for a bootstrap, etc. */ /* XXX these should be defined per controller (or drive) elsewhere, not here! */ #if defined(__i386__) || defined(__amd64__) || defined(__arm__) || \ defined(__powerpc__) || defined(__mips__) #define LABELSECTOR 1 /* sector containing label */ #define LABELOFFSET 0 /* offset of label in sector */ #endif #define DISKMAGIC ((u_int32_t)0x82564557) /* The disk magic number */ #ifndef MAXPARTITIONS #define MAXPARTITIONS 8 #endif /* Size of bootblock area in sector-size neutral bytes */ #define BBSIZE 8192 #define LABEL_PART 2 /* partition containing label */ #define RAW_PART 2 /* partition containing whole disk */ #define SWAP_PART 1 /* partition normally containing swap */ struct disklabel { u_int32_t d_magic; /* the magic number */ u_int16_t d_type; /* drive type */ u_int16_t d_subtype; /* controller/d_type specific */ char d_typename[16]; /* type name, e.g. "eagle" */ char d_packname[16]; /* pack identifier */ /* disk geometry: */ u_int32_t d_secsize; /* # of bytes per sector */ u_int32_t d_nsectors; /* # of data sectors per track */ u_int32_t d_ntracks; /* # of tracks per cylinder */ u_int32_t d_ncylinders; /* # of data cylinders per unit */ u_int32_t d_secpercyl; /* # of data sectors per cylinder */ u_int32_t d_secperunit; /* # of data sectors per unit */ /* * Spares (bad sector replacements) below are not counted in * d_nsectors or d_secpercyl. Spare sectors are assumed to * be physical sectors which occupy space at the end of each * track and/or cylinder. */ u_int16_t d_sparespertrack; /* # of spare sectors per track */ u_int16_t d_sparespercyl; /* # of spare sectors per cylinder */ /* * Alternate cylinders include maintenance, replacement, configuration * description areas, etc. */ u_int32_t d_acylinders; /* # of alt. cylinders per unit */ /* hardware characteristics: */ /* * d_interleave, d_trackskew and d_cylskew describe perturbations * in the media format used to compensate for a slow controller. * Interleave is physical sector interleave, set up by the * formatter or controller when formatting. When interleaving is * in use, logically adjacent sectors are not physically * contiguous, but instead are separated by some number of * sectors. It is specified as the ratio of physical sectors * traversed per logical sector. Thus an interleave of 1:1 * implies contiguous layout, while 2:1 implies that logical * sector 0 is separated by one sector from logical sector 1. * d_trackskew is the offset of sector 0 on track N relative to * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew * is the offset of sector 0 on cylinder N relative to sector 0 * on cylinder N-1. */ u_int16_t d_rpm; /* rotational speed */ u_int16_t d_interleave; /* hardware sector interleave */ u_int16_t d_trackskew; /* sector 0 skew, per track */ u_int16_t d_cylskew; /* sector 0 skew, per cylinder */ u_int32_t d_headswitch; /* head switch time, usec */ u_int32_t d_trkseek; /* track-to-track seek, usec */ u_int32_t d_flags; /* generic flags */ #define NDDATA 5 u_int32_t d_drivedata[NDDATA]; /* drive-type specific information */ #define NSPARE 5 u_int32_t d_spare[NSPARE]; /* reserved for future use */ u_int32_t d_magic2; /* the magic number (again) */ u_int16_t d_checksum; /* xor of data incl. partitions */ /* filesystem and partition information: */ u_int16_t d_npartitions; /* number of partitions in following */ u_int32_t d_bbsize; /* size of boot area at sn0, bytes */ u_int32_t d_sbsize; /* max size of fs superblock, bytes */ struct partition { /* the partition table */ u_int32_t p_size; /* number of sectors in partition */ u_int32_t p_offset; /* starting sector */ u_int32_t p_fsize; /* filesystem basic fragment size */ u_int8_t p_fstype; /* filesystem type, see below */ u_int8_t p_frag; /* filesystem fragments per block */ u_int16_t p_cpg; /* filesystem cylinders per group */ } d_partitions[MAXPARTITIONS]; /* actually may be more */ }; #ifdef CTASSERT CTASSERT(sizeof(struct disklabel) == 148 + MAXPARTITIONS * 16); #endif static __inline u_int16_t dkcksum(struct disklabel *lp); static __inline u_int16_t dkcksum(struct disklabel *lp) { u_int16_t *start, *end; u_int16_t sum = 0; start = (u_int16_t *)lp; end = (u_int16_t *)&lp->d_partitions[lp->d_npartitions]; while (start < end) sum ^= *start++; return (sum); } /* d_type values: */ #define DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */ #define DTYPE_MSCP 2 /* MSCP */ #define DTYPE_DEC 3 /* other DEC (rk, rl) */ #define DTYPE_SCSI 4 /* SCSI */ #define DTYPE_ESDI 5 /* ESDI interface */ #define DTYPE_ST506 6 /* ST506 etc. */ #define DTYPE_HPIB 7 /* CS/80 on HP-IB */ #define DTYPE_HPFL 8 /* HP Fiber-link */ #define DTYPE_FLOPPY 10 /* floppy */ #define DTYPE_CCD 11 /* concatenated disk */ #define DTYPE_VINUM 12 /* vinum volume */ #define DTYPE_DOC2K 13 /* Msys DiskOnChip */ #define DTYPE_RAID 14 /* CMU RAIDFrame */ #define DTYPE_JFS2 16 /* IBM JFS 2 */ #ifdef DKTYPENAMES static const char *dktypenames[] = { "unknown", "SMD", "MSCP", "old DEC", "SCSI", "ESDI", "ST506", "HP-IB", "HP-FL", "type 9", "floppy", "CCD", "Vinum", "DOC2K", "Raid", "?", "jfs", NULL }; #define DKMAXTYPES (sizeof(dktypenames) / sizeof(dktypenames[0]) - 1) #endif /* * Filesystem type and version. * Used to interpret other filesystem-specific * per-partition information. */ #define FS_UNUSED 0 /* unused */ #define FS_SWAP 1 /* swap */ #define FS_V6 2 /* Sixth Edition */ #define FS_V7 3 /* Seventh Edition */ #define FS_SYSV 4 /* System V */ #define FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ #define FS_V8 6 /* Eighth Edition, 4K blocks */ #define FS_BSDFFS 7 /* 4.2BSD fast filesystem */ #define FS_MSDOS 8 /* MSDOS filesystem */ #define FS_BSDLFS 9 /* 4.4BSD log-structured filesystem */ #define FS_OTHER 10 /* in use, but unknown/unsupported */ #define FS_HPFS 11 /* OS/2 high-performance filesystem */ #define FS_ISO9660 12 /* ISO 9660, normally CD-ROM */ #define FS_BOOT 13 /* partition contains bootstrap */ #define FS_VINUM 14 /* Vinum drive */ #define FS_RAID 15 /* RAIDFrame drive */ #define FS_FILECORE 16 /* Acorn Filecore Filing System */ #define FS_EXT2FS 17 /* ext2fs */ #define FS_NTFS 18 /* Windows/NT file system */ #define FS_CCD 20 /* concatenated disk component */ #define FS_JFS2 21 /* IBM JFS2 */ #define FS_HAMMER 22 /* DragonFlyBSD Hammer FS */ #define FS_HAMMER2 23 /* DragonFlyBSD Hammer2 FS */ #define FS_UDF 24 /* UDF */ #define FS_EFS 26 /* SGI's Extent File system */ #define FS_ZFS 27 /* Sun's ZFS */ #define FS_NANDFS 30 /* FreeBSD nandfs (NiLFS derived) */ #ifdef FSTYPENAMES static const char *fstypenames[] = { "unused", "swap", "Version 6", "Version 7", "System V", "4.1BSD", "Eighth Edition", "4.2BSD", "MSDOS", "4.4LFS", "unknown", "HPFS", "ISO9660", "boot", "vinum", "raid", "Filecore", "EXT2FS", "NTFS", "?", "ccd", "jfs", "HAMMER", "HAMMER2", "UDF", "?", "EFS", "ZFS", "?", "?", "nandfs", NULL }; #define FSMAXTYPES (sizeof(fstypenames) / sizeof(fstypenames[0]) - 1) #endif /* * flags shared by various drives: */ #define D_REMOVABLE 0x01 /* removable media */ #define D_ECC 0x02 /* supports ECC */ #define D_BADSECT 0x04 /* supports bad sector forw. */ #define D_RAMDISK 0x08 /* disk emulator */ #define D_CHAIN 0x10 /* can do back-back transfers */ /* - * Disklabel-specific ioctls. - * * NB: defines ioctls from 'd'/128 and up. */ - /* get and set disklabel */ -#define DIOCGDINFO _IOR('d', 101, struct disklabel)/* get */ -#define DIOCSDINFO _IOW('d', 102, struct disklabel)/* set */ -#define DIOCWDINFO _IOW('d', 103, struct disklabel)/* set, update disk */ -#define DIOCBSDBB _IOW('d', 110, void *) /* write bootblocks */ /* * Functions for proper encoding/decoding of struct disklabel into/from * bytestring. */ void bsd_partition_le_dec(u_char *ptr, struct partition *d); int bsd_disklabel_le_dec(u_char *ptr, struct disklabel *d, int maxpart); void bsd_partition_le_enc(u_char *ptr, struct partition *d); void bsd_disklabel_le_enc(u_char *ptr, struct disklabel *d); #ifndef _KERNEL __BEGIN_DECLS struct disklabel *getdiskbyname(const char *); __END_DECLS #endif #endif /* !_SYS_DISKLABEL_H_ */