1 /* $NetBSD: newfs.c,v 1.31 1997/11/19 09:48:52 drochner 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.13 (Berkeley) 5/1/95"; 45 #else 46 __RCSID("$NetBSD: newfs.c,v 1.31 1997/11/19 09:48:52 drochner 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 #include <sys/wait.h> 61 62 #include <ufs/ufs/dir.h> 63 #include <ufs/ufs/dinode.h> 64 #include <ufs/ffs/fs.h> 65 66 #include <ctype.h> 67 #include <errno.h> 68 #include <paths.h> 69 #include <stdio.h> 70 #include <stdlib.h> 71 #include <string.h> 72 #include <syslog.h> 73 #include <unistd.h> 74 #include <signal.h> 75 #include <err.h> 76 #include <util.h> 77 78 #include "mntopts.h" 79 #include "dkcksum.h" 80 #include "extern.h" 81 82 struct mntopt mopts[] = { 83 MOPT_STDOPTS, 84 MOPT_ASYNC, 85 MOPT_UPDATE, 86 MOPT_NOATIME, 87 { NULL }, 88 }; 89 90 static struct disklabel *getdisklabel __P((char *, int)); 91 static void rewritelabel __P((char *, int, struct disklabel *)); 92 static void usage __P((void)); 93 int main __P((int, char *[])); 94 95 #define COMPAT /* allow non-labeled disks */ 96 97 /* 98 * The following two constants set the default block and fragment sizes. 99 * Both constants must be a power of 2 and meet the following constraints: 100 * MINBSIZE <= DESBLKSIZE <= MAXBSIZE 101 * sectorsize <= DESFRAGSIZE <= DESBLKSIZE 102 * DESBLKSIZE / DESFRAGSIZE <= 8 103 */ 104 #define DFL_FRAGSIZE 1024 105 #define DFL_BLKSIZE 8192 106 107 /* 108 * Cylinder groups may have up to many cylinders. The actual 109 * number used depends upon how much information can be stored 110 * on a single cylinder. The default is to use 16 cylinders 111 * per group. 112 */ 113 #define DESCPG 16 /* desired fs_cpg */ 114 115 /* 116 * ROTDELAY gives the minimum number of milliseconds to initiate 117 * another disk transfer on the same cylinder. It is used in 118 * determining the rotationally optimal layout for disk blocks 119 * within a file; the default of fs_rotdelay is 0ms. 120 */ 121 #define ROTDELAY 0 122 123 /* 124 * MAXBLKPG determines the maximum number of data blocks which are 125 * placed in a single cylinder group. The default is one indirect 126 * block worth of data blocks. 127 */ 128 #define MAXBLKPG(bsize) ((bsize) / sizeof(daddr_t)) 129 130 /* 131 * Each file system has a number of inodes statically allocated. 132 * We allocate one inode slot per NFPI fragments, expecting this 133 * to be far more than we will ever need. 134 */ 135 #define NFPI 4 136 137 /* 138 * For each cylinder we keep track of the availability of blocks at different 139 * rotational positions, so that we can lay out the data to be picked 140 * up with minimum rotational latency. NRPOS is the default number of 141 * rotational positions that we distinguish. With NRPOS of 8 the resolution 142 * of our summary information is 2ms for a typical 3600 rpm drive. Caching 143 * and zoning pretty much defeats rotational optimization, so we now use a 144 * default of 1. 145 */ 146 #define NRPOS 1 /* number distinct rotational positions */ 147 148 149 int mfs; /* run as the memory based filesystem */ 150 int Nflag; /* run without writing file system */ 151 int Oflag; /* format as an 4.3BSD file system */ 152 int fssize; /* file system size */ 153 int ntracks; /* # tracks/cylinder */ 154 int nsectors; /* # sectors/track */ 155 int nphyssectors; /* # sectors/track including spares */ 156 int secpercyl; /* sectors per cylinder */ 157 int trackspares = -1; /* spare sectors per track */ 158 int cylspares = -1; /* spare sectors per cylinder */ 159 int sectorsize; /* bytes/sector */ 160 int rpm; /* revolutions/minute of drive */ 161 int interleave; /* hardware sector interleave */ 162 int trackskew = -1; /* sector 0 skew, per track */ 163 int headswitch; /* head switch time, usec */ 164 int trackseek; /* track-to-track seek, usec */ 165 int fsize = 0; /* fragment size */ 166 int bsize = 0; /* block size */ 167 int cpg = DESCPG; /* cylinders/cylinder group */ 168 int cpgflg; /* cylinders/cylinder group flag was given */ 169 int minfree = MINFREE; /* free space threshold */ 170 int opt = DEFAULTOPT; /* optimization preference (space or time) */ 171 int density; /* number of bytes per inode */ 172 int maxcontig = 8; /* max contiguous blocks to allocate */ 173 int rotdelay = ROTDELAY; /* rotational delay between blocks */ 174 int maxbpg; /* maximum blocks per file in a cyl group */ 175 int nrpos = NRPOS; /* # of distinguished rotational positions */ 176 int bbsize = BBSIZE; /* boot block size */ 177 int sbsize = SBSIZE; /* superblock size */ 178 int mntflags = MNT_ASYNC; /* flags to be passed to mount */ 179 u_long memleft; /* virtual memory available */ 180 caddr_t membase; /* start address of memory based filesystem */ 181 #ifdef COMPAT 182 char *disktype; 183 int unlabeled; 184 #endif 185 186 char device[MAXPATHLEN]; 187 extern char *__progname; 188 189 int 190 main(argc, argv) 191 int argc; 192 char *argv[]; 193 { 194 int ch; 195 struct partition *pp; 196 struct disklabel *lp; 197 struct disklabel mfsfakelabel; 198 struct partition oldpartition; 199 struct stat st; 200 struct statfs *mp; 201 int fsi = 0, fso, len, n, maxpartitions; 202 char *cp = NULL, *s1, *s2, *special, *opstring; 203 #ifdef MFS 204 char mountfromname[100]; 205 pid_t pid, res; 206 struct statfs sf; 207 int status; 208 #endif 209 210 if (strstr(__progname, "mfs")) { 211 mfs = 1; 212 Nflag++; 213 } 214 215 maxpartitions = getmaxpartitions(); 216 if (maxpartitions > 26) 217 errx(1, "insane maxpartitions value %d", maxpartitions); 218 219 opstring = mfs ? 220 "NT:a:b:c:d:e:f:i:m:o:s:" : 221 "NOS:T:a:b:c:d:e:f:i:k:l:m:n:o:p:r:s:t:u:x:"; 222 while ((ch = getopt(argc, argv, opstring)) != -1) 223 switch (ch) { 224 case 'N': 225 Nflag = 1; 226 break; 227 case 'O': 228 Oflag = 1; 229 break; 230 case 'S': 231 if ((sectorsize = atoi(optarg)) <= 0) 232 errx(1, "%s: bad sector size", optarg); 233 break; 234 #ifdef COMPAT 235 case 'T': 236 disktype = optarg; 237 break; 238 #endif 239 case 'a': 240 if ((maxcontig = atoi(optarg)) <= 0) 241 errx(1, "%s: bad maximum contiguous blocks", 242 optarg); 243 break; 244 case 'b': 245 if ((bsize = atoi(optarg)) < MINBSIZE) 246 errx(1, "%s: bad block size", optarg); 247 break; 248 case 'c': 249 if ((cpg = atoi(optarg)) <= 0) 250 errx(1, "%s: bad cylinders/group", optarg); 251 cpgflg++; 252 break; 253 case 'd': 254 if ((rotdelay = atoi(optarg)) < 0) 255 errx(1, "%s: bad rotational delay", optarg); 256 break; 257 case 'e': 258 if ((maxbpg = atoi(optarg)) <= 0) 259 errx(1, "%s: bad blocks per file in a cylinder group", 260 optarg); 261 break; 262 case 'f': 263 if ((fsize = atoi(optarg)) <= 0) 264 errx(1, "%s: bad fragment size", optarg); 265 break; 266 case 'i': 267 if ((density = atoi(optarg)) <= 0) 268 errx(1, "%s: bad bytes per inode", optarg); 269 break; 270 case 'k': 271 if ((trackskew = atoi(optarg)) < 0) 272 errx(1, "%s: bad track skew", optarg); 273 break; 274 case 'l': 275 if ((interleave = atoi(optarg)) <= 0) 276 errx(1, "%s: bad interleave", optarg); 277 break; 278 case 'm': 279 if ((minfree = atoi(optarg)) < 0 || minfree > 99) 280 errx(1, "%s: bad free space %%", optarg); 281 break; 282 case 'n': 283 if ((nrpos = atoi(optarg)) <= 0) 284 errx(1, "%s: bad rotational layout count", 285 optarg); 286 break; 287 case 'o': 288 if (mfs) 289 getmntopts(optarg, mopts, &mntflags, 0); 290 else { 291 if (strcmp(optarg, "space") == 0) 292 opt = FS_OPTSPACE; 293 else if (strcmp(optarg, "time") == 0) 294 opt = FS_OPTTIME; 295 else 296 errx(1, "%s %s", 297 "unknown optimization preference: ", 298 "use `space' or `time'."); 299 } 300 break; 301 case 'p': 302 if ((trackspares = atoi(optarg)) < 0) 303 errx(1, "%s: bad spare sectors per track", 304 optarg); 305 break; 306 case 'r': 307 if ((rpm = atoi(optarg)) <= 0) 308 errx(1, "%s: bad revolutions/minute", optarg); 309 break; 310 case 's': 311 if ((fssize = atoi(optarg)) <= 0) 312 errx(1, "%s: bad file system size", optarg); 313 break; 314 case 't': 315 if ((ntracks = atoi(optarg)) <= 0) 316 errx(1, "%s: bad total tracks", optarg); 317 break; 318 case 'u': 319 if ((nsectors = atoi(optarg)) <= 0) 320 errx(1, "%s: bad sectors/track", optarg); 321 break; 322 case 'x': 323 if ((cylspares = atoi(optarg)) < 0) 324 errx(1, "%s: bad spare sectors per cylinder", 325 optarg); 326 break; 327 case '?': 328 default: 329 usage(); 330 } 331 argc -= optind; 332 argv += optind; 333 334 if (argc != 2 && (mfs || argc != 1)) 335 usage(); 336 337 special = argv[0]; 338 if (mfs && !strcmp(special, "swap")) { 339 /* 340 * it's an MFS, mounted on "swap." fake up a label. 341 * XXX XXX XXX 342 */ 343 fso = -1; /* XXX; normally done below. */ 344 345 memset(&mfsfakelabel, 0, sizeof(mfsfakelabel)); 346 mfsfakelabel.d_secsize = 512; 347 mfsfakelabel.d_nsectors = 64; 348 mfsfakelabel.d_ntracks = 16; 349 mfsfakelabel.d_ncylinders = 16; 350 mfsfakelabel.d_secpercyl = 1024; 351 mfsfakelabel.d_secperunit = 16384; 352 mfsfakelabel.d_rpm = 3600; 353 mfsfakelabel.d_interleave = 1; 354 mfsfakelabel.d_npartitions = 1; 355 mfsfakelabel.d_partitions[0].p_size = 16384; 356 mfsfakelabel.d_partitions[0].p_fsize = 1024; 357 mfsfakelabel.d_partitions[0].p_frag = 8; 358 mfsfakelabel.d_partitions[0].p_cpg = 16; 359 360 lp = &mfsfakelabel; 361 pp = &mfsfakelabel.d_partitions[0]; 362 363 goto havelabel; 364 } 365 cp = strrchr(special, '/'); 366 if (cp == 0) { 367 /* 368 * No path prefix; try /dev/r%s then /dev/%s. 369 */ 370 (void)sprintf(device, "%sr%s", _PATH_DEV, special); 371 if (stat(device, &st) == -1) 372 (void)sprintf(device, "%s%s", _PATH_DEV, special); 373 special = device; 374 } 375 if (Nflag) { 376 fso = -1; 377 } else { 378 fso = open(special, O_WRONLY); 379 if (fso < 0) 380 err(1, "%s: open", special); 381 382 /* Bail if target special is mounted */ 383 n = getmntinfo(&mp, MNT_NOWAIT); 384 if (n == 0) 385 err(1, "%s: getmntinfo", special); 386 387 len = sizeof(_PATH_DEV) - 1; 388 s1 = special; 389 if (strncmp(_PATH_DEV, s1, len) == 0) 390 s1 += len; 391 392 while (--n >= 0) { 393 s2 = mp->f_mntfromname; 394 if (strncmp(_PATH_DEV, s2, len) == 0) { 395 s2 += len - 1; 396 *s2 = 'r'; 397 } 398 if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) 399 errx(1, "%s is mounted on %s", 400 special, mp->f_mntonname); 401 ++mp; 402 } 403 } 404 if (mfs && disktype != NULL) { 405 lp = (struct disklabel *)getdiskbyname(disktype); 406 if (lp == NULL) 407 errx(1, "%s: unknown disk type", disktype); 408 pp = &lp->d_partitions[1]; 409 } else { 410 fsi = open(special, O_RDONLY); 411 if (fsi < 0) 412 err(1, "%s: open", special); 413 if (fstat(fsi, &st) < 0) 414 err(1, "%s: fstat", special); 415 if (!S_ISCHR(st.st_mode) && !mfs) 416 warnx("%s: not a character-special device", special); 417 cp = strchr(argv[0], '\0') - 1; 418 if (cp == 0 || ((*cp < 'a' || *cp > ('a' + maxpartitions - 1)) 419 && !isdigit(*cp))) 420 errx(1, "can't figure out file system partition"); 421 #ifdef COMPAT 422 if (!mfs && disktype == NULL) 423 disktype = argv[1]; 424 #endif 425 lp = getdisklabel(special, fsi); 426 if (isdigit(*cp)) 427 pp = &lp->d_partitions[0]; 428 else 429 pp = &lp->d_partitions[*cp - 'a']; 430 if (pp->p_size == 0) 431 errx(1, "`%c' partition is unavailable", *cp); 432 if (pp->p_fstype == FS_BOOT) 433 errx(1, "`%c' partition overlaps boot program", *cp); 434 } 435 havelabel: 436 if (fssize == 0) 437 fssize = pp->p_size; 438 if (fssize > pp->p_size && !mfs) 439 errx(1, "maximum file system size on the `%c' partition is %d", 440 *cp, pp->p_size); 441 if (rpm == 0) { 442 rpm = lp->d_rpm; 443 if (rpm <= 0) 444 rpm = 3600; 445 } 446 if (ntracks == 0) { 447 ntracks = lp->d_ntracks; 448 if (ntracks <= 0) 449 errx(1, "no default #tracks"); 450 } 451 if (nsectors == 0) { 452 nsectors = lp->d_nsectors; 453 if (nsectors <= 0) 454 errx(1, "no default #sectors/track"); 455 } 456 if (sectorsize == 0) { 457 sectorsize = lp->d_secsize; 458 if (sectorsize <= 0) 459 errx(1, "no default sector size"); 460 } 461 if (trackskew == -1) { 462 trackskew = lp->d_trackskew; 463 if (trackskew < 0) 464 trackskew = 0; 465 } 466 if (interleave == 0) { 467 interleave = lp->d_interleave; 468 if (interleave <= 0) 469 interleave = 1; 470 } 471 if (fsize == 0) { 472 fsize = pp->p_fsize; 473 if (fsize <= 0) 474 fsize = MAX(DFL_FRAGSIZE, lp->d_secsize); 475 } 476 if (bsize == 0) { 477 bsize = pp->p_frag * pp->p_fsize; 478 if (bsize <= 0) 479 bsize = MIN(DFL_BLKSIZE, 8 * fsize); 480 } 481 /* 482 * Maxcontig sets the default for the maximum number of blocks 483 * that may be allocated sequentially. With filesystem clustering 484 * it is possible to allocate contiguous blocks up to the maximum 485 * transfer size permitted by the controller or buffering. 486 */ 487 if (maxcontig == 0) 488 maxcontig = MAX(1, MIN(MAXPHYS, MAXBSIZE) / bsize); 489 if (density == 0) 490 density = NFPI * fsize; 491 if (minfree < MINFREE && opt != FS_OPTSPACE) { 492 warnx("%s %s %d%%", "Warning: changing optimization to space", 493 "because minfree is less than", MINFREE); 494 opt = FS_OPTSPACE; 495 } 496 if (trackspares == -1) { 497 trackspares = lp->d_sparespertrack; 498 if (trackspares < 0) 499 trackspares = 0; 500 } 501 nphyssectors = nsectors + trackspares; 502 if (cylspares == -1) { 503 cylspares = lp->d_sparespercyl; 504 if (cylspares < 0) 505 cylspares = 0; 506 } 507 secpercyl = nsectors * ntracks - cylspares; 508 if (secpercyl != lp->d_secpercyl) 509 warnx("%s (%d) %s (%u)\n", 510 "Warning: calculated sectors per cylinder", secpercyl, 511 "disagrees with disk label", lp->d_secpercyl); 512 if (maxbpg == 0) 513 maxbpg = MAXBLKPG(bsize); 514 headswitch = lp->d_headswitch; 515 trackseek = lp->d_trkseek; 516 #ifdef notdef /* label may be 0 if faked up by kernel */ 517 bbsize = lp->d_bbsize; 518 sbsize = lp->d_sbsize; 519 #endif 520 oldpartition = *pp; 521 mkfs(pp, special, fsi, fso); 522 if (!Nflag && memcmp(pp, &oldpartition, sizeof(oldpartition))) 523 rewritelabel(special, fso, lp); 524 if (!Nflag) 525 close(fso); 526 close(fsi); 527 #ifdef MFS 528 if (mfs) { 529 struct mfs_args args; 530 531 switch (pid = fork()) { 532 case -1: 533 perror("mfs"); 534 exit(10); 535 case 0: 536 sprintf(mountfromname, "mfs:%d", getpid()); 537 break; 538 default: 539 sprintf(mountfromname, "mfs:%d", pid); 540 for (;;) { 541 /* 542 * spin until the mount succeeds 543 * or the child exits 544 */ 545 usleep(1); 546 547 /* 548 * XXX Here is a race condition: another process 549 * can mount a filesystem which hides our 550 * ramdisk before we see the success. 551 */ 552 if (statfs(argv[1], &sf) < 0) 553 err(88, "statfs %s", argv[1]); 554 if (!strcmp(sf.f_mntfromname, mountfromname) && 555 !strncmp(sf.f_mntonname, argv[1], 556 MNAMELEN) && 557 !strcmp(sf.f_fstypename, "mfs")) 558 exit(0); 559 560 res = waitpid(pid, &status, WNOHANG); 561 if (res == -1) 562 err(11, "waitpid"); 563 if (res != pid) 564 continue; 565 if (WIFEXITED(status)) { 566 if (WEXITSTATUS(status) == 0) 567 exit(0); 568 errx(1, "%s: mount: %s", argv[1], 569 strerror(WEXITSTATUS(status))); 570 } else 571 errx(11, "abnormal termination"); 572 } 573 /* NOTREACHED */ 574 } 575 576 (void) setsid(); 577 (void) close(0); 578 (void) close(1); 579 (void) close(2); 580 (void) chdir("/"); 581 582 args.fspec = mountfromname; 583 args.export.ex_root = -2; 584 if (mntflags & MNT_RDONLY) 585 args.export.ex_flags = MNT_EXRDONLY; 586 else 587 args.export.ex_flags = 0; 588 args.base = membase; 589 args.size = fssize * sectorsize; 590 if (mount(MOUNT_MFS, argv[1], mntflags, &args) < 0) 591 exit(errno); /* parent prints message */ 592 } 593 #endif 594 exit(0); 595 } 596 597 #ifdef COMPAT 598 char lmsg[] = "%s: can't read disk label; disk type must be specified"; 599 #else 600 char lmsg[] = "%s: can't read disk label"; 601 #endif 602 603 static struct disklabel * 604 getdisklabel(s, fd) 605 char *s; 606 volatile int fd; 607 { 608 static struct disklabel lab; 609 610 if (ioctl(fd, DIOCGDINFO, &lab) < 0) { 611 #ifdef COMPAT 612 if (disktype) { 613 struct disklabel *lp; 614 615 unlabeled++; 616 lp = getdiskbyname(disktype); 617 if (lp == NULL) 618 errx(1, "%s: unknown disk type", disktype); 619 return (lp); 620 } 621 #endif 622 warn("ioctl (GDINFO)"); 623 errx(1, lmsg, s); 624 } 625 return (&lab); 626 } 627 628 static void 629 rewritelabel(s, fd, lp) 630 char *s; 631 volatile int fd; 632 struct disklabel *lp; 633 { 634 #ifdef COMPAT 635 if (unlabeled) 636 return; 637 #endif 638 lp->d_checksum = 0; 639 lp->d_checksum = dkcksum(lp); 640 if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { 641 warn("ioctl (WDINFO)"); 642 errx(1, "%s: can't rewrite disk label", s); 643 } 644 #if vax 645 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 646 int i; 647 int cfd; 648 daddr_t alt; 649 char specname[64]; 650 char blk[1024]; 651 char *cp; 652 653 /* 654 * Make name for 'c' partition. 655 */ 656 strcpy(specname, s); 657 cp = specname + strlen(specname) - 1; 658 if (!isdigit(*cp)) 659 *cp = 'c'; 660 cfd = open(specname, O_WRONLY); 661 if (cfd < 0) 662 err(1, "%s: open", specname); 663 memset(blk, 0, sizeof(blk)); 664 *(struct disklabel *)(blk + LABELOFFSET) = *lp; 665 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 666 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 667 off_t offset; 668 669 offset = alt + i; 670 offset *= lp->d_secsize; 671 if (lseek(cfd, offset, SEEK_SET) == -1) 672 err(1, "lseek to badsector area: "); 673 if (write(cfd, blk, lp->d_secsize) < lp->d_secsize) 674 warn("alternate label %d write", i/2); 675 } 676 close(cfd); 677 } 678 #endif 679 } 680 681 static void 682 usage() 683 { 684 if (mfs) { 685 fprintf(stderr, 686 "usage: %s [ -fsoptions ] special-device mount-point\n", 687 __progname); 688 } else 689 fprintf(stderr, 690 "usage: %s [ -fsoptions ] special-device%s\n", 691 __progname, 692 #ifdef COMPAT 693 " [device-type]"); 694 #else 695 ""); 696 #endif 697 fprintf(stderr, "where fsoptions are:\n"); 698 fprintf(stderr, 699 "\t-N do not create file system, just print out parameters\n"); 700 fprintf(stderr, "\t-O create a 4.3BSD format filesystem\n"); 701 fprintf(stderr, "\t-S sector size\n"); 702 #ifdef COMPAT 703 fprintf(stderr, "\t-T disktype\n"); 704 #endif 705 fprintf(stderr, "\t-a maximum contiguous blocks\n"); 706 fprintf(stderr, "\t-b block size\n"); 707 fprintf(stderr, "\t-c cylinders/group\n"); 708 fprintf(stderr, "\t-d rotational delay between contiguous blocks\n"); 709 fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n"); 710 fprintf(stderr, "\t-f frag size\n"); 711 fprintf(stderr, "\t-i number of bytes per inode\n"); 712 fprintf(stderr, "\t-k sector 0 skew, per track\n"); 713 fprintf(stderr, "\t-l hardware sector interleave\n"); 714 fprintf(stderr, "\t-m minimum free space %%\n"); 715 fprintf(stderr, "\t-n number of distinguished rotational positions\n"); 716 fprintf(stderr, "\t-o optimization preference (`space' or `time')\n"); 717 fprintf(stderr, "\t-p spare sectors per track\n"); 718 fprintf(stderr, "\t-s file system size (sectors)\n"); 719 fprintf(stderr, "\t-r revolutions/minute\n"); 720 fprintf(stderr, "\t-t tracks/cylinder\n"); 721 fprintf(stderr, "\t-u sectors/track\n"); 722 fprintf(stderr, "\t-x spare sectors per cylinder\n"); 723 exit(1); 724 } 725