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