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