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