home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / newfs / newfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-03  |  17.1 KB  |  612 lines

  1. /*
  2.  * Copyright (c) 1983, 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)newfs.c    6.27 (Berkeley) 7/3/91";
  36. #endif /* not lint */
  37.  
  38. #ifndef lint
  39. char copyright[] =
  40. "@(#) Copyright (c) 1983, 1989 Regents of the University of California.\n\
  41.  All rights reserved.\n";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * newfs: friendly front end to mkfs
  46.  */
  47. #include <sys/param.h>
  48. #include <sys/stat.h>
  49. #include <ufs/fs.h>
  50. #include <ufs/dir.h>
  51. #include <sys/ioctl.h>
  52. #include <sys/disklabel.h>
  53. #include <sys/file.h>
  54. #include <sys/mount.h>
  55.  
  56. #include <errno.h>
  57. #include <stdarg.h>
  58. #include <stdio.h>
  59. #include <ctype.h>
  60. #include <string.h>
  61. #include <stdlib.h>
  62. #include <paths.h>
  63.  
  64. #define    COMPAT            /* allow non-labeled disks */
  65.  
  66. /*
  67.  * The following two constants set the default block and fragment sizes.
  68.  * Both constants must be a power of 2 and meet the following constraints:
  69.  *    MINBSIZE <= DESBLKSIZE <= MAXBSIZE
  70.  *    sectorsize <= DESFRAGSIZE <= DESBLKSIZE
  71.  *    DESBLKSIZE / DESFRAGSIZE <= 8
  72.  */
  73. #define    DFL_FRAGSIZE    1024
  74. #define    DFL_BLKSIZE    8192
  75.  
  76. /*
  77.  * Cylinder groups may have up to many cylinders. The actual
  78.  * number used depends upon how much information can be stored
  79.  * on a single cylinder. The default is to use 16 cylinders
  80.  * per group.
  81.  */
  82. #define    DESCPG        16    /* desired fs_cpg */
  83.  
  84. /*
  85.  * MINFREE gives the minimum acceptable percentage of file system
  86.  * blocks which may be free. If the freelist drops below this level
  87.  * only the superuser may continue to allocate blocks. This may
  88.  * be set to 0 if no reserve of free blocks is deemed necessary,
  89.  * however throughput drops by fifty percent if the file system
  90.  * is run at between 90% and 100% full; thus the default value of
  91.  * fs_minfree is 10%. With 10% free space, fragmentation is not a
  92.  * problem, so we choose to optimize for time.
  93.  */
  94. #define MINFREE        10
  95. #define DEFAULTOPT    FS_OPTTIME
  96.  
  97. /*
  98.  * ROTDELAY gives the minimum number of milliseconds to initiate
  99.  * another disk transfer on the same cylinder. It is used in
  100.  * determining the rotationally optimal layout for disk blocks
  101.  * within a file; the default of fs_rotdelay is 4ms.
  102.  */
  103. #define ROTDELAY    4
  104.  
  105. /*
  106.  * MAXCONTIG sets the default for the maximum number of blocks
  107.  * that may be allocated sequentially. Since UNIX drivers are
  108.  * not capable of scheduling multi-block transfers, this defaults
  109.  * to 1 (ie no contiguous blocks are allocated).
  110.  */
  111. #define MAXCONTIG    1
  112.  
  113. /*
  114.  * MAXBLKPG determines the maximum number of data blocks which are
  115.  * placed in a single cylinder group. The default is one indirect
  116.  * block worth of data blocks.
  117.  */
  118. #define MAXBLKPG(bsize)    ((bsize) / sizeof(daddr_t))
  119.  
  120. /*
  121.  * Each file system has a number of inodes statically allocated.
  122.  * We allocate one inode slot per NFPI fragments, expecting this
  123.  * to be far more than we will ever need.
  124.  */
  125. #define    NFPI        4
  126.  
  127. /*
  128.  * For each cylinder we keep track of the availability of blocks at different
  129.  * rotational positions, so that we can lay out the data to be picked
  130.  * up with minimum rotational latency.  NRPOS is the default number of
  131.  * rotational positions that we distinguish.  With NRPOS of 8 the resolution
  132.  * of our summary information is 2ms for a typical 3600 rpm drive.
  133.  */
  134. #define    NRPOS        8    /* number distinct rotational positions */
  135.  
  136.  
  137. int    mfs;            /* run as the memory based filesystem */
  138. int    Nflag;            /* run without writing file system */
  139. int    fssize;            /* file system size */
  140. int    ntracks;        /* # tracks/cylinder */
  141. int    nsectors;        /* # sectors/track */
  142. int    nphyssectors;        /* # sectors/track including spares */
  143. int    secpercyl;        /* sectors per cylinder */
  144. int    trackspares = -1;    /* spare sectors per track */
  145. int    cylspares = -1;        /* spare sectors per cylinder */
  146. int    sectorsize;        /* bytes/sector */
  147. #ifdef tahoe
  148. int    realsectorsize;        /* bytes/sector in hardware */
  149. #endif
  150. int    rpm;            /* revolutions/minute of drive */
  151. int    interleave;        /* hardware sector interleave */
  152. int    trackskew = -1;        /* sector 0 skew, per track */
  153. int    headswitch;        /* head switch time, usec */
  154. int    trackseek;        /* track-to-track seek, usec */
  155. int    fsize = 0;        /* fragment size */
  156. int    bsize = 0;        /* block size */
  157. int    cpg = DESCPG;        /* cylinders/cylinder group */
  158. int    cpgflg;            /* cylinders/cylinder group flag was given */
  159. int    minfree = MINFREE;    /* free space threshold */
  160. int    opt = DEFAULTOPT;    /* optimization preference (space or time) */
  161. int    density;        /* number of bytes per inode */
  162. int    maxcontig = MAXCONTIG;    /* max contiguous blocks to allocate */
  163. int    rotdelay = ROTDELAY;    /* rotational delay between blocks */
  164. int    maxbpg;            /* maximum blocks per file in a cyl group */
  165. int    nrpos = NRPOS;        /* # of distinguished rotational positions */
  166. int    bbsize = BBSIZE;    /* boot block size */
  167. int    sbsize = SBSIZE;    /* superblock size */
  168. int    mntflags;        /* flags to be passed to mount */
  169. u_long    memleft;        /* virtual memory available */
  170. caddr_t    membase;        /* start address of memory based filesystem */
  171. #ifdef COMPAT
  172. char    *disktype;
  173. int    unlabeled;
  174. #endif
  175.  
  176. char    device[MAXPATHLEN];
  177. char    *progname;
  178.  
  179. main(argc, argv)
  180.     int argc;
  181.     char *argv[];
  182. {
  183.     extern char *optarg;
  184.     extern int optind;
  185.     register int ch;
  186.     register struct partition *pp;
  187.     register struct disklabel *lp;
  188.     struct disklabel *getdisklabel();
  189.     struct partition oldpartition;
  190.     struct stat st;
  191.     int fsi, fso;
  192.     char *cp, *special, *opstring, buf[BUFSIZ];
  193.  
  194.     if (progname = rindex(*argv, '/'))
  195.         ++progname;
  196.     else
  197.         progname = *argv;
  198.  
  199.     if (strstr(progname, "mfs")) {
  200.         mfs = 1;
  201.         Nflag++;
  202.     }
  203.  
  204.     opstring = "F:NS:T:a:b:c:d:e:f:i:k:l:m:n:o:p:r:s:t:u:x:";
  205.     if (!mfs)
  206.         opstring += 2;        /* -F is mfs only */
  207.  
  208.     while ((ch = getopt(argc, argv, opstring)) != EOF)
  209.         switch(ch) {
  210.         case 'F':
  211.             if ((mntflags = atoi(optarg)) == 0)
  212.                 fatal("%s: bad mount flags", optarg);
  213.             break;
  214.         case 'N':
  215.             Nflag++;
  216.             break;
  217.         case 'S':
  218.             if ((sectorsize = atoi(optarg)) <= 0)
  219.                 fatal("%s: bad sector size", optarg);
  220.             break;
  221. #ifdef COMPAT
  222.         case 'T':
  223.             disktype = optarg;
  224.             break;
  225. #endif
  226.         case 'a':
  227.             if ((maxcontig = atoi(optarg)) <= 0)
  228.                 fatal("%s: bad max contiguous blocks\n",
  229.                     optarg);
  230.             break;
  231.         case 'b':
  232.             if ((bsize = atoi(optarg)) < MINBSIZE)
  233.                 fatal("%s: bad block size", optarg);
  234.             break;
  235.         case 'c':
  236.             if ((cpg = atoi(optarg)) <= 0)
  237.                 fatal("%s: bad cylinders/group", optarg);
  238.             cpgflg++;
  239.             break;
  240.         case 'd':
  241.             if ((rotdelay = atoi(optarg)) < 0)
  242.                 fatal("%s: bad rotational delay\n", optarg);
  243.             break;
  244.         case 'e':
  245.             if ((maxbpg = atoi(optarg)) <= 0)
  246.                 fatal("%s: bad blocks per file in a cyl group\n",
  247.                     optarg);
  248.             break;
  249.         case 'f':
  250.             if ((fsize = atoi(optarg)) <= 0)
  251.                 fatal("%s: bad frag size", optarg);
  252.             break;
  253.         case 'i':
  254.             if ((density = atoi(optarg)) <= 0)
  255.                 fatal("%s: bad bytes per inode\n", optarg);
  256.             break;
  257.         case 'k':
  258.             if ((trackskew = atoi(optarg)) < 0)
  259.                 fatal("%s: bad track skew", optarg);
  260.             break;
  261.         case 'l':
  262.             if ((interleave = atoi(optarg)) <= 0)
  263.                 fatal("%s: bad interleave", optarg);
  264.             break;
  265.         case 'm':
  266.             if ((minfree = atoi(optarg)) < 0 || minfree > 99)
  267.                 fatal("%s: bad free space %%\n", optarg);
  268.             break;
  269.         case 'n':
  270.             if ((nrpos = atoi(optarg)) <= 0)
  271.                 fatal("%s: bad rotational layout count\n",
  272.                     optarg);
  273.             break;
  274.         case 'o':
  275.             if (strcmp(optarg, "space") == 0)
  276.                 opt = FS_OPTSPACE;
  277.             else if (strcmp(optarg, "time") == 0)
  278.                 opt = FS_OPTTIME;
  279.             else
  280.                 fatal("%s: bad optimization preference %s",
  281.                     optarg, "(options are `space' or `time')");
  282.             break;
  283.         case 'p':
  284.             if ((trackspares = atoi(optarg)) < 0)
  285.                 fatal("%s: bad spare sectors per track",
  286.                     optarg);
  287.             break;
  288.         case 'r':
  289.             if ((rpm = atoi(optarg)) <= 0)
  290.                 fatal("%s: bad revs/minute\n", optarg);
  291.             break;
  292.         case 's':
  293.             if ((fssize = atoi(optarg)) <= 0)
  294.                 fatal("%s: bad file system size", optarg);
  295.             break;
  296.         case 't':
  297.             if ((ntracks = atoi(optarg)) <= 0)
  298.                 fatal("%s: bad total tracks", optarg);
  299.             break;
  300.         case 'u':
  301.             if ((nsectors = atoi(optarg)) <= 0)
  302.                 fatal("%s: bad sectors/track", optarg);
  303.             break;
  304.         case 'x':
  305.             if ((cylspares = atoi(optarg)) < 0)
  306.                 fatal("%s: bad spare sectors per cylinder",
  307.                     optarg);
  308.             break;
  309.         case '?':
  310.         default:
  311.             usage();
  312.         }
  313.     argc -= optind;
  314.     argv += optind;
  315.  
  316.     if (argc != 2 && (mfs || argc != 1))
  317.         usage();
  318.  
  319.     special = argv[0];
  320.     cp = rindex(special, '/');
  321.     if (cp == 0) {
  322.         /*
  323.          * No path prefix; try /dev/r%s then /dev/%s.
  324.          */
  325.         (void)sprintf(device, "%sr%s", _PATH_DEV, special);
  326.         if (stat(device, &st) == -1)
  327.             (void)sprintf(device, "%s%s", _PATH_DEV, special);
  328.         special = device;
  329.     }
  330.     if (!Nflag) {
  331.         fso = open(special, O_WRONLY);
  332.         if (fso < 0)
  333.             fatal("%s: %s", special, strerror(errno));
  334.     } else
  335.         fso = -1;
  336.     fsi = open(special, O_RDONLY);
  337.     if (fsi < 0)
  338.         fatal("%s: %s", special, strerror(errno));
  339.     if (fstat(fsi, &st) < 0)
  340.         fatal("%s: %s", special, strerror(errno));
  341.     if ((st.st_mode & S_IFMT) != S_IFCHR && !mfs)
  342.         printf("%s: %s: not a character-special device\n",
  343.             progname, special);
  344.     cp = index(argv[0], '\0') - 1;
  345.     if (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp))
  346.         fatal("%s: can't figure out file system partition", argv[0]);
  347. #ifdef COMPAT
  348.     if (!mfs && disktype == NULL)
  349.         disktype = argv[1];
  350. #endif
  351.     lp = getdisklabel(special, fsi);
  352.     if (isdigit(*cp))
  353.         pp = &lp->d_partitions[0];
  354.     else
  355.         pp = &lp->d_partitions[*cp - 'a'];
  356.     if (pp->p_size == 0)
  357.         fatal("%s: `%c' partition is unavailable", argv[0], *cp);
  358.     if (fssize == 0)
  359.         fssize = pp->p_size;
  360.     if (fssize > pp->p_size && !mfs)
  361.            fatal("%s: maximum file system size on the `%c' partition is %d",
  362.             argv[0], *cp, pp->p_size);
  363.     if (rpm == 0) {
  364.         rpm = lp->d_rpm;
  365.         if (rpm <= 0)
  366.             rpm = 3600;
  367.     }
  368.     if (ntracks == 0) {
  369.         ntracks = lp->d_ntracks;
  370.         if (ntracks <= 0)
  371.             fatal("%s: no default #tracks", argv[0]);
  372.     }
  373.     if (nsectors == 0) {
  374.         nsectors = lp->d_nsectors;
  375.         if (nsectors <= 0)
  376.             fatal("%s: no default #sectors/track", argv[0]);
  377.     }
  378.     if (sectorsize == 0) {
  379.         sectorsize = lp->d_secsize;
  380.         if (sectorsize <= 0)
  381.             fatal("%s: no default sector size", argv[0]);
  382.     }
  383.     if (trackskew == -1) {
  384.         trackskew = lp->d_trackskew;
  385.         if (trackskew < 0)
  386.             trackskew = 0;
  387.     }
  388.     if (interleave == 0) {
  389.         interleave = lp->d_interleave;
  390.         if (interleave <= 0)
  391.             interleave = 1;
  392.     }
  393.     if (fsize == 0) {
  394.         fsize = pp->p_fsize;
  395.         if (fsize <= 0)
  396.             fsize = MAX(DFL_FRAGSIZE, lp->d_secsize);
  397.     }
  398.     if (bsize == 0) {
  399.         bsize = pp->p_frag * pp->p_fsize;
  400.         if (bsize <= 0)
  401.             bsize = MIN(DFL_BLKSIZE, 8 * fsize);
  402.     }
  403.     if (density == 0)
  404.         density = NFPI * fsize;
  405.     if (minfree < 10 && opt != FS_OPTSPACE) {
  406.         fprintf(stderr, "Warning: changing optimization to space ");
  407.         fprintf(stderr, "because minfree is less than 10%%\n");
  408.         opt = FS_OPTSPACE;
  409.     }
  410.     if (trackspares == -1) {
  411.         trackspares = lp->d_sparespertrack;
  412.         if (trackspares < 0)
  413.             trackspares = 0;
  414.     }
  415.     nphyssectors = nsectors + trackspares;
  416.     if (cylspares == -1) {
  417.         cylspares = lp->d_sparespercyl;
  418.         if (cylspares < 0)
  419.             cylspares = 0;
  420.     }
  421.     secpercyl = nsectors * ntracks - cylspares;
  422.     if (secpercyl != lp->d_secpercyl)
  423.         fprintf(stderr, "%s (%d) %s (%lu)\n",
  424.             "Warning: calculated sectors per cylinder", secpercyl,
  425.             "disagrees with disk label", lp->d_secpercyl);
  426.     if (maxbpg == 0)
  427.         maxbpg = MAXBLKPG(bsize);
  428.     headswitch = lp->d_headswitch;
  429.     trackseek = lp->d_trkseek;
  430. #ifdef notdef /* label may be 0 if faked up by kernel */
  431.     bbsize = lp->d_bbsize;
  432.     sbsize = lp->d_sbsize;
  433. #endif
  434.     oldpartition = *pp;
  435. #ifdef tahoe
  436.     realsectorsize = sectorsize;
  437.     if (sectorsize != DEV_BSIZE) {        /* XXX */
  438.         int secperblk = DEV_BSIZE / sectorsize;
  439.  
  440.         sectorsize = DEV_BSIZE;
  441.         nsectors /= secperblk;
  442.         nphyssectors /= secperblk;
  443.         secpercyl /= secperblk;
  444.         fssize /= secperblk;
  445.         pp->p_size /= secperblk;
  446.     }
  447. #endif
  448.     mkfs(pp, special, fsi, fso);
  449. #ifdef tahoe
  450.     if (realsectorsize != DEV_BSIZE)
  451.         pp->p_size *= DEV_BSIZE / realsectorsize;
  452. #endif
  453.     if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition)))
  454.         rewritelabel(special, fso, lp);
  455.     if (!Nflag)
  456.         close(fso);
  457.     close(fsi);
  458. #ifdef MFS
  459.     if (mfs) {
  460.         struct mfs_args args;
  461.  
  462.         sprintf(buf, "mfs:%d", getpid());
  463.         args.name = buf;
  464.         args.base = membase;
  465.         args.size = fssize * sectorsize;
  466.         if (mount(MOUNT_MFS, argv[1], mntflags, &args) < 0)
  467.             fatal("%s: %s", argv[1], strerror(errno));
  468.     }
  469. #endif
  470.     exit(0);
  471. }
  472.  
  473. #ifdef COMPAT
  474. char lmsg[] = "%s: can't read disk label; disk type must be specified";
  475. #else
  476. char lmsg[] = "%s: can't read disk label";
  477. #endif
  478.  
  479. struct disklabel *
  480. getdisklabel(s, fd)
  481.     char *s;
  482.     int fd;
  483. {
  484.     static struct disklabel lab;
  485.  
  486.     if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
  487. #ifdef COMPAT
  488.         if (disktype) {
  489.             struct disklabel *lp, *getdiskbyname();
  490.  
  491.             unlabeled++;
  492.             lp = getdiskbyname(disktype);
  493.             if (lp == NULL)
  494.                 fatal("%s: unknown disk type", disktype);
  495.             return (lp);
  496.         }
  497. #endif
  498.         (void)fprintf(stderr,
  499.             "%s: ioctl (GDINFO): %s\n", progname, strerror(errno));
  500.         fatal(lmsg, s);
  501.     }
  502.     return (&lab);
  503. }
  504.  
  505. rewritelabel(s, fd, lp)
  506.     char *s;
  507.     int fd;
  508.     register struct disklabel *lp;
  509. {
  510. #ifdef COMPAT
  511.     if (unlabeled)
  512.         return;
  513. #endif
  514.     lp->d_checksum = 0;
  515.     lp->d_checksum = dkcksum(lp);
  516.     if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) {
  517.         (void)fprintf(stderr,
  518.             "%s: ioctl (WDINFO): %s\n", progname, strerror(errno));
  519.         fatal("%s: can't rewrite disk label", s);
  520.     }
  521. #if vax
  522.     if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
  523.         register i;
  524.         int cfd;
  525.         daddr_t alt;
  526.         char specname[64];
  527.         char blk[1024];
  528.         char *cp;
  529.  
  530.         /*
  531.          * Make name for 'c' partition.
  532.          */
  533.         strcpy(specname, s);
  534.         cp = specname + strlen(specname) - 1;
  535.         if (!isdigit(*cp))
  536.             *cp = 'c';
  537.         cfd = open(specname, O_WRONLY);
  538.         if (cfd < 0)
  539.             fatal("%s: %s", specname, strerror(errno));
  540.         bzero(blk, sizeof(blk));
  541.         *(struct disklabel *)(blk + LABELOFFSET) = *lp;
  542.         alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
  543.         for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
  544.             if (lseek(cfd, (off_t)(alt + i) * lp->d_secsize,
  545.                 L_SET) == -1)
  546.                 fatal("lseek to badsector area: %s",
  547.                     strerror(errno));
  548.             if (write(cfd, blk, lp->d_secsize) < lp->d_secsize)
  549.                 fprintf(stderr,
  550.                     "%s: alternate label %d write: %s\n",
  551.                     progname, i/2, strerror(errno));
  552.         }
  553.         close(cfd);
  554.     }
  555. #endif
  556. }
  557.  
  558. /*VARARGS*/
  559. fatal(fmt)
  560.     char *fmt;
  561. {
  562.     va_list ap;
  563.  
  564.     fprintf(stderr, "%s: ", progname);
  565.     va_start(ap, fmt);
  566.     (void)vfprintf(stderr, fmt, ap);
  567.     va_end(ap);
  568.     putc('\n', stderr);
  569.     exit(1);
  570. }
  571.  
  572. usage()
  573. {
  574.     if (mfs) {
  575.         fprintf(stderr,
  576.             "usage: mfs [ -fsoptions ] special-device mount-point\n");
  577.     } else
  578.         fprintf(stderr,
  579.             "usage: newfs [ -fsoptions ] special-device%s\n",
  580. #ifdef COMPAT
  581.             " [device-type]");
  582. #else
  583.             "");
  584. #endif
  585.     fprintf(stderr, "where fsoptions are:\n");
  586.     fprintf(stderr,
  587.         "\t-N do not create file system, just print out parameters\n");
  588.     fprintf(stderr, "\t-S sector size\n");
  589. #ifdef COMPAT
  590.     fprintf(stderr, "\t-T disktype\n");
  591. #endif
  592.     fprintf(stderr, "\t-a maximum contiguous blocks\n");
  593.     fprintf(stderr, "\t-b block size\n");
  594.     fprintf(stderr, "\t-c cylinders/group\n");
  595.     fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
  596.     fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
  597.     fprintf(stderr, "\t-f frag size\n");
  598.     fprintf(stderr, "\t-i number of bytes per inode\n");
  599.     fprintf(stderr, "\t-k sector 0 skew, per track\n");
  600.     fprintf(stderr, "\t-l hardware sector interleave\n");
  601.     fprintf(stderr, "\t-m minimum free space %%\n");
  602.     fprintf(stderr, "\t-n number of distinguished rotational positions\n");
  603.     fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
  604.     fprintf(stderr, "\t-p spare sectors per track\n");
  605.     fprintf(stderr, "\t-s file system size (sectors)\n");
  606.     fprintf(stderr, "\t-r revolutions/minute\n");
  607.     fprintf(stderr, "\t-t tracks/cylinder\n");
  608.     fprintf(stderr, "\t-u sectors/track\n");
  609.     fprintf(stderr, "\t-x spare sectors per cylinder\n");
  610.     exit(1);
  611. }
  612.