1 /* 2 * Copyright (c) 1983, 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char sccsid[] = "@(#)newfs.c 6.28 (Berkeley) 8/6/91"; 36 #endif /* not lint */ 37 38 #ifndef lint 39 char copyright[] = 40 "@(#) Copyright (c) 1983, 1989 Regents of the University of California.\n\ 41 All rights reserved.\n"; 42 #endif /* not lint */ 43 44 /* 45 * newfs: friendly front end to mkfs 46 */ 47 #include <sys/param.h> 48 #include <sys/stat.h> 49 #include <sys/ioctl.h> 50 #include <sys/disklabel.h> 51 #include <sys/file.h> 52 #include <sys/mount.h> 53 54 #include <ufs/ufs/dir.h> 55 #include <ufs/ufs/dinode.h> 56 #include <ufs/ffs/fs.h> 57 58 #include <errno.h> 59 #include <unistd.h> 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <ctype.h> 63 #include <string.h> 64 #include <paths.h> 65 #include "config.h" 66 #include "extern.h" 67 68 #define COMPAT /* allow non-labeled disks */ 69 70 int mfs; /* run as the memory based filesystem */ 71 int Nflag; /* run without writing file system */ 72 int fssize; /* file system size */ 73 int ntracks; /* # tracks/cylinder */ 74 int nsectors; /* # sectors/track */ 75 int nphyssectors; /* # sectors/track including spares */ 76 int secpercyl; /* sectors per cylinder */ 77 int trackspares = -1; /* spare sectors per track */ 78 int cylspares = -1; /* spare sectors per cylinder */ 79 int sectorsize; /* bytes/sector */ 80 #ifdef tahoe 81 int realsectorsize; /* bytes/sector in hardware */ 82 #endif 83 int rpm; /* revolutions/minute of drive */ 84 int interleave; /* hardware sector interleave */ 85 int trackskew = -1; /* sector 0 skew, per track */ 86 int headswitch; /* head switch time, usec */ 87 int trackseek; /* track-to-track seek, usec */ 88 int fsize = 0; /* fragment size */ 89 int bsize = 0; /* block size */ 90 int cpg = DESCPG; /* cylinders/cylinder group */ 91 int cpgflg; /* cylinders/cylinder group flag was given */ 92 int minfree = MINFREE; /* free space threshold */ 93 int opt = DEFAULTOPT; /* optimization preference (space or time) */ 94 int density; /* number of bytes per inode */ 95 int maxcontig = MAXCONTIG; /* max contiguous blocks to allocate */ 96 int rotdelay = ROTDELAY; /* rotational delay between blocks */ 97 int maxbpg; /* maximum blocks per file in a cyl group */ 98 int nrpos = NRPOS; /* # of distinguished rotational positions */ 99 int bbsize = BBSIZE; /* boot block size */ 100 int sbsize = SBSIZE; /* superblock size */ 101 int mntflags; /* flags to be passed to mount */ 102 u_long memleft; /* virtual memory available */ 103 caddr_t membase; /* start address of memory based filesystem */ 104 #ifdef COMPAT 105 char *disktype; 106 int unlabeled; 107 #endif 108 109 char device[MAXPATHLEN]; 110 char *progname, *special; 111 112 static struct disklabel *getdisklabel __P((char *, int)); 113 static struct disklabel *debug_readlabel __P((int)); 114 static void rewritelabel __P((char *, int, struct disklabel *)); 115 static void usage __P((void)); 116 117 int 118 main(argc, argv) 119 int argc; 120 char *argv[]; 121 { 122 register int ch; 123 register struct partition *pp; 124 register struct disklabel *lp; 125 struct partition oldpartition; 126 struct stat st; 127 int debug, lfs, fsi, fso, segsize; 128 char *cp, *opstring; 129 130 if (progname = rindex(*argv, '/')) 131 ++progname; 132 else 133 progname = *argv; 134 135 if (strstr(progname, "mfs")) { 136 mfs = 1; 137 Nflag++; 138 } 139 140 /* -F is mfs only and MUST come first! */ 141 opstring = "F:B:DLNS:T:a:b:c:d:e:f:i:k:l:m:n:o:p:r:s:t:u:x:"; 142 if (!mfs) 143 opstring += 2; 144 145 debug = lfs = segsize = 0; 146 while ((ch = getopt(argc, argv, opstring)) != EOF) 147 switch(ch) { 148 case 'B': /* LFS segment size */ 149 if ((segsize = atoi(optarg)) < LFS_MINSEGSIZE) 150 fatal("%s: bad segment size", optarg); 151 break; 152 case 'D': 153 debug = 1; 154 break; 155 case 'F': 156 if ((mntflags = atoi(optarg)) == 0) 157 fatal("%s: bad mount flags", optarg); 158 break; 159 case 'L': /* Create lfs */ 160 lfs = 1; 161 break; 162 case 'N': 163 Nflag++; 164 break; 165 case 'S': 166 if ((sectorsize = atoi(optarg)) <= 0) 167 fatal("%s: bad sector size", optarg); 168 break; 169 #ifdef COMPAT 170 case 'T': 171 disktype = optarg; 172 break; 173 #endif 174 case 'a': 175 if ((maxcontig = atoi(optarg)) <= 0) 176 fatal("%s: bad max contiguous blocks\n", 177 optarg); 178 break; 179 case 'b': /* used for LFS */ 180 if ((bsize = atoi(optarg)) < MINBSIZE) 181 fatal("%s: bad block size", optarg); 182 break; 183 case 'c': 184 if ((cpg = atoi(optarg)) <= 0) 185 fatal("%s: bad cylinders/group", optarg); 186 cpgflg++; 187 break; 188 case 'd': 189 if ((rotdelay = atoi(optarg)) < 0) 190 fatal("%s: bad rotational delay\n", optarg); 191 break; 192 case 'e': 193 if ((maxbpg = atoi(optarg)) <= 0) 194 fatal("%s: bad blocks per file in a cyl group\n", 195 optarg); 196 break; 197 case 'f': 198 if ((fsize = atoi(optarg)) <= 0) 199 fatal("%s: bad frag size", optarg); 200 break; 201 case 'i': 202 if ((density = atoi(optarg)) <= 0) 203 fatal("%s: bad bytes per inode\n", optarg); 204 break; 205 case 'k': 206 if ((trackskew = atoi(optarg)) < 0) 207 fatal("%s: bad track skew", optarg); 208 break; 209 case 'l': 210 if ((interleave = atoi(optarg)) <= 0) 211 fatal("%s: bad interleave", optarg); 212 break; 213 case 'm': /* used for LFS */ 214 if ((minfree = atoi(optarg)) < 0 || minfree > 99) 215 fatal("%s: bad free space %%\n", optarg); 216 break; 217 case 'n': 218 if ((nrpos = atoi(optarg)) <= 0) 219 fatal("%s: bad rotational layout count\n", 220 optarg); 221 break; 222 case 'o': 223 if (strcmp(optarg, "space") == 0) 224 opt = FS_OPTSPACE; 225 else if (strcmp(optarg, "time") == 0) 226 opt = FS_OPTTIME; 227 else 228 fatal("%s: bad optimization preference %s", 229 optarg, "(options are `space' or `time')"); 230 break; 231 case 'p': 232 if ((trackspares = atoi(optarg)) < 0) 233 fatal("%s: bad spare sectors per track", 234 optarg); 235 break; 236 case 'r': 237 if ((rpm = atoi(optarg)) <= 0) 238 fatal("%s: bad revs/minute\n", optarg); 239 break; 240 case 's': /* used for LFS */ 241 if ((fssize = atoi(optarg)) <= 0) 242 fatal("%s: bad file system size", optarg); 243 break; 244 case 't': 245 if ((ntracks = atoi(optarg)) <= 0) 246 fatal("%s: bad total tracks", optarg); 247 break; 248 case 'u': 249 if ((nsectors = atoi(optarg)) <= 0) 250 fatal("%s: bad sectors/track", optarg); 251 break; 252 case 'x': 253 if ((cylspares = atoi(optarg)) < 0) 254 fatal("%s: bad spare sectors per cylinder", 255 optarg); 256 break; 257 case '?': 258 default: 259 usage(); 260 } 261 argc -= optind; 262 argv += optind; 263 264 if (argc != 2 && (mfs || argc != 1)) 265 usage(); 266 267 /* 268 * If the -N flag isn't specified, open the output file. If no path 269 * prefix, try /dev/r%s and then /dev/%s. 270 */ 271 special = argv[0]; 272 if (index(special, '/') == NULL) { 273 (void)sprintf(device, "%sr%s", _PATH_DEV, special); 274 if (stat(device, &st) == -1) 275 (void)sprintf(device, "%s%s", _PATH_DEV, special); 276 special = device; 277 } 278 if (!Nflag) { 279 fso = open(special, 280 (debug ? O_CREAT : 0) | O_WRONLY, DEFFILEMODE); 281 if (fso < 0) 282 fatal("%s: %s", special, strerror(errno)); 283 } else 284 fso = -1; 285 286 /* Open the input file. */ 287 fsi = open(special, O_RDONLY); 288 if (fsi < 0) 289 fatal("%s: %s", special, strerror(errno)); 290 if (fstat(fsi, &st) < 0) 291 fatal("%s: %s", special, strerror(errno)); 292 293 if (!debug && !mfs && !S_ISCHR(st.st_mode)) 294 (void)printf("%s: %s: not a character-special device\n", 295 progname, special); 296 cp = index(argv[0], '\0') - 1; 297 if (!debug && (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp))) 298 fatal("%s: can't figure out file system partition", argv[0]); 299 300 #ifdef COMPAT 301 if (!mfs && disktype == NULL) 302 disktype = argv[1]; 303 #endif 304 if (debug) 305 lp = debug_readlabel(fsi); 306 else 307 lp = getdisklabel(special, fsi); 308 309 if (isdigit(*cp)) 310 pp = &lp->d_partitions[0]; 311 else 312 pp = &lp->d_partitions[*cp - 'a']; 313 if (pp->p_size == 0) 314 fatal("%s: `%c' partition is unavailable", argv[0], *cp); 315 316 /* If we're making a LFS, we break out here */ 317 if (lfs) 318 exit(make_lfs(fso, lp, pp, minfree, bsize, segsize)); 319 320 if (fssize == 0) 321 fssize = pp->p_size; 322 if (fssize > pp->p_size && !mfs) 323 fatal("%s: maximum file system size on the `%c' partition is %d", 324 argv[0], *cp, pp->p_size); 325 if (rpm == 0) { 326 rpm = lp->d_rpm; 327 if (rpm <= 0) 328 rpm = 3600; 329 } 330 if (ntracks == 0) { 331 ntracks = lp->d_ntracks; 332 if (ntracks <= 0) 333 fatal("%s: no default #tracks", argv[0]); 334 } 335 if (nsectors == 0) { 336 nsectors = lp->d_nsectors; 337 if (nsectors <= 0) 338 fatal("%s: no default #sectors/track", argv[0]); 339 } 340 if (sectorsize == 0) { 341 sectorsize = lp->d_secsize; 342 if (sectorsize <= 0) 343 fatal("%s: no default sector size", argv[0]); 344 } 345 if (trackskew == -1) { 346 trackskew = lp->d_trackskew; 347 if (trackskew < 0) 348 trackskew = 0; 349 } 350 if (interleave == 0) { 351 interleave = lp->d_interleave; 352 if (interleave <= 0) 353 interleave = 1; 354 } 355 if (fsize == 0) { 356 fsize = pp->p_fsize; 357 if (fsize <= 0) 358 fsize = MAX(DFL_FRAGSIZE, lp->d_secsize); 359 } 360 if (bsize == 0) { 361 bsize = pp->p_frag * pp->p_fsize; 362 if (bsize <= 0) 363 bsize = MIN(DFL_BLKSIZE, 8 * fsize); 364 } 365 if (density == 0) 366 density = NFPI * fsize; 367 if (minfree < 10 && opt != FS_OPTSPACE) { 368 fprintf(stderr, "Warning: changing optimization to space "); 369 fprintf(stderr, "because minfree is less than 10%%\n"); 370 opt = FS_OPTSPACE; 371 } 372 if (trackspares == -1) { 373 trackspares = lp->d_sparespertrack; 374 if (trackspares < 0) 375 trackspares = 0; 376 } 377 nphyssectors = nsectors + trackspares; 378 if (cylspares == -1) { 379 cylspares = lp->d_sparespercyl; 380 if (cylspares < 0) 381 cylspares = 0; 382 } 383 secpercyl = nsectors * ntracks - cylspares; 384 if (secpercyl != lp->d_secpercyl) 385 fprintf(stderr, "%s (%d) %s (%lu)\n", 386 "Warning: calculated sectors per cylinder", secpercyl, 387 "disagrees with disk label", lp->d_secpercyl); 388 if (maxbpg == 0) 389 maxbpg = MAXBLKPG(bsize); 390 headswitch = lp->d_headswitch; 391 trackseek = lp->d_trkseek; 392 #ifdef notdef /* label may be 0 if faked up by kernel */ 393 bbsize = lp->d_bbsize; 394 sbsize = lp->d_sbsize; 395 #endif 396 oldpartition = *pp; 397 #ifdef tahoe 398 realsectorsize = sectorsize; 399 if (sectorsize != DEV_BSIZE) { /* XXX */ 400 int secperblk = DEV_BSIZE / sectorsize; 401 402 sectorsize = DEV_BSIZE; 403 nsectors /= secperblk; 404 nphyssectors /= secperblk; 405 secpercyl /= secperblk; 406 fssize /= secperblk; 407 pp->p_size /= secperblk; 408 } 409 #endif 410 mkfs(pp, special, fsi, fso); 411 #ifdef tahoe 412 if (realsectorsize != DEV_BSIZE) 413 pp->p_size *= DEV_BSIZE / realsectorsize; 414 #endif 415 if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition))) 416 rewritelabel(special, fso, lp); 417 if (!Nflag) 418 close(fso); 419 close(fsi); 420 #ifdef MFS 421 if (mfs) { 422 struct mfs_args args; 423 char buf[50]; 424 425 (void)sprintf(buf, "mfs:%d", getpid()); 426 args.name = buf; 427 args.base = membase; 428 args.size = fssize * sectorsize; 429 if (mount(MOUNT_MFS, argv[1], mntflags, &args) < 0) 430 fatal("%s: %s", argv[1], strerror(errno)); 431 } 432 #endif 433 exit(0); 434 } 435 436 #ifdef COMPAT 437 char lmsg[] = "%s: can't read disk label; disk type must be specified"; 438 #else 439 char lmsg[] = "%s: can't read disk label"; 440 #endif 441 442 static struct disklabel * 443 getdisklabel(s, fd) 444 char *s; 445 int fd; 446 { 447 static struct disklabel lab; 448 449 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { 450 #ifdef COMPAT 451 if (disktype) { 452 struct disklabel *lp, *getdiskbyname(); 453 454 unlabeled++; 455 lp = getdiskbyname(disktype); 456 if (lp == NULL) 457 fatal("%s: unknown disk type", disktype); 458 return (lp); 459 } 460 #endif 461 (void)fprintf(stderr, 462 "%s: ioctl (GDINFO): %s\n", progname, strerror(errno)); 463 fatal(lmsg, s); 464 } 465 return (&lab); 466 } 467 468 469 static struct disklabel * 470 debug_readlabel(fd) 471 int fd; 472 { 473 static struct disklabel lab; 474 int n; 475 476 if ((n = read(fd, &lab, sizeof(struct disklabel))) < 0) 477 fatal("unable to read disk label: %s", strerror(errno)); 478 else if (n < sizeof(struct disklabel)) 479 fatal("short read of disklabel: %d of %d bytes", n, 480 sizeof(struct disklabel)); 481 return(&lab); 482 } 483 484 static void 485 rewritelabel(s, fd, lp) 486 char *s; 487 int fd; 488 register struct disklabel *lp; 489 { 490 #ifdef COMPAT 491 if (unlabeled) 492 return; 493 #endif 494 lp->d_checksum = 0; 495 lp->d_checksum = dkcksum(lp); 496 if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { 497 (void)fprintf(stderr, 498 "%s: ioctl (WDINFO): %s\n", progname, strerror(errno)); 499 fatal("%s: can't rewrite disk label", s); 500 } 501 #if vax 502 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 503 register i; 504 int cfd; 505 daddr_t alt; 506 char specname[64]; 507 char blk[1024]; 508 char *cp; 509 510 /* 511 * Make name for 'c' partition. 512 */ 513 strcpy(specname, s); 514 cp = specname + strlen(specname) - 1; 515 if (!isdigit(*cp)) 516 *cp = 'c'; 517 cfd = open(specname, O_WRONLY); 518 if (cfd < 0) 519 fatal("%s: %s", specname, strerror(errno)); 520 bzero(blk, sizeof(blk)); 521 *(struct disklabel *)(blk + LABELOFFSET) = *lp; 522 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 523 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 524 if (lseek(cfd, (off_t)(alt + i) * lp->d_secsize, 525 L_SET) == -1) 526 fatal("lseek to badsector area: %s", 527 strerror(errno)); 528 if (write(cfd, blk, lp->d_secsize) < lp->d_secsize) 529 fprintf(stderr, 530 "%s: alternate label %d write: %s\n", 531 progname, i/2, strerror(errno)); 532 } 533 close(cfd); 534 } 535 #endif 536 } 537 538 void 539 usage() 540 { 541 if (mfs) { 542 fprintf(stderr, 543 "usage: mfs [ -fsoptions ] special-device mount-point\n"); 544 } else 545 fprintf(stderr, 546 "usage: newfs [ -fsoptions ] special-device%s\n", 547 #ifdef COMPAT 548 " [device-type]"); 549 #else 550 ""); 551 #endif 552 fprintf(stderr, "where fsoptions are:\n"); 553 fprintf(stderr, "\t-B LFS segment size\n"); 554 fprintf(stderr, "\t-D debug\n"); 555 fprintf(stderr, "\t-F mount flags\n"); 556 fprintf(stderr, "\t-L create LFS file system\n"); 557 fprintf(stderr, 558 "\t-N do not create file system, just print out parameters\n"); 559 fprintf(stderr, "\t-S sector size\n"); 560 #ifdef COMPAT 561 fprintf(stderr, "\t-T disktype\n"); 562 #endif 563 fprintf(stderr, "\t-a maximum contiguous blocks\n"); 564 fprintf(stderr, "\t-b block size\n"); 565 fprintf(stderr, "\t-c cylinders/group\n"); 566 fprintf(stderr, "\t-d rotational delay between contiguous blocks\n"); 567 fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n"); 568 fprintf(stderr, "\t-f frag size\n"); 569 fprintf(stderr, "\t-i number of bytes per inode\n"); 570 fprintf(stderr, "\t-k sector 0 skew, per track\n"); 571 fprintf(stderr, "\t-l hardware sector interleave\n"); 572 fprintf(stderr, "\t-m minimum free space %%\n"); 573 fprintf(stderr, "\t-n number of distinguished rotational positions\n"); 574 fprintf(stderr, "\t-o optimization preference (`space' or `time')\n"); 575 fprintf(stderr, "\t-p spare sectors per track\n"); 576 fprintf(stderr, "\t-r revolutions/minute\n"); 577 fprintf(stderr, "\t-s file system size (sectors)\n"); 578 fprintf(stderr, "\t-t tracks/cylinder\n"); 579 fprintf(stderr, "\t-u sectors/track\n"); 580 fprintf(stderr, "\t-x spare sectors per cylinder\n"); 581 exit(1); 582 } 583