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