121159Sdist /* 221159Sdist * Copyright (c) 1983 Regents of the University of California. 321159Sdist * All rights reserved. The Berkeley software License Agreement 421159Sdist * specifies the terms and conditions for redistribution. 521159Sdist */ 621159Sdist 710762Ssam #ifndef lint 821159Sdist char copyright[] = 921159Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1021159Sdist All rights reserved.\n"; 1121159Sdist #endif not lint 1210762Ssam 1321159Sdist #ifndef lint 14*30380Smckusick static char sccsid[] = "@(#)newfs.c 6.1 (Berkeley) 01/13/87"; 1521159Sdist #endif not lint 1621159Sdist 1710762Ssam /* 1811069Ssam * newfs: friendly front end to mkfs 1910762Ssam */ 2010762Ssam #include <sys/param.h> 2110762Ssam #include <sys/stat.h> 2210762Ssam #include <sys/fs.h> 2313603Ssam #include <sys/dir.h> 24*30380Smckusick #include <sys/ioctl.h> 25*30380Smckusick #include <sys/disklabel.h> 26*30380Smckusick #include <sys/file.h> 2710762Ssam 2810762Ssam #include <stdio.h> 29*30380Smckusick #include <ctype.h> 3010762Ssam 31*30380Smckusick /* 32*30380Smckusick * The following two constants set the default block and fragment sizes. 33*30380Smckusick * Both constants must be a power of 2 and meet the following constraints: 34*30380Smckusick * MINBSIZE <= DESBLKSIZE <= MAXBSIZE 35*30380Smckusick * sectorsize <= DESFRAGSIZE <= DESBLKSIZE 36*30380Smckusick * DESBLKSIZE / DESFRAGSIZE <= 8 37*30380Smckusick */ 38*30380Smckusick #define DFL_FRAGSIZE 1024 39*30380Smckusick #define DFL_BLKSIZE 8192 4011183Ssam 41*30380Smckusick /* 42*30380Smckusick * Cylinder groups may have up to MAXCPG cylinders. The actual 43*30380Smckusick * number used depends upon how much information can be stored 44*30380Smckusick * on a single cylinder. The default is to used 16 cylinders 45*30380Smckusick * per group. 46*30380Smckusick */ 47*30380Smckusick #define DESCPG 16 /* desired fs_cpg */ 48*30380Smckusick 49*30380Smckusick /* 50*30380Smckusick * MINFREE gives the minimum acceptable percentage of file system 51*30380Smckusick * blocks which may be free. If the freelist drops below this level 52*30380Smckusick * only the superuser may continue to allocate blocks. This may 53*30380Smckusick * be set to 0 if no reserve of free blocks is deemed necessary, 54*30380Smckusick * however throughput drops by fifty percent if the file system 55*30380Smckusick * is run at between 90% and 100% full; thus the default value of 56*30380Smckusick * fs_minfree is 10%. With 10% free space, fragmentation is not a 57*30380Smckusick * problem, so we choose to optimize for time. 58*30380Smckusick */ 59*30380Smckusick #define MINFREE 10 60*30380Smckusick #define DEFAULTOPT FS_OPTTIME 61*30380Smckusick 62*30380Smckusick /* 63*30380Smckusick * ROTDELAY gives the minimum number of milliseconds to initiate 64*30380Smckusick * another disk transfer on the same cylinder. It is used in 65*30380Smckusick * determining the rotationally optimal layout for disk blocks 66*30380Smckusick * within a file; the default of fs_rotdelay is 4ms. 67*30380Smckusick */ 68*30380Smckusick #define ROTDELAY 4 69*30380Smckusick 70*30380Smckusick /* 71*30380Smckusick * MAXCONTIG sets the default for the maximum number of blocks 72*30380Smckusick * that may be allocated sequentially. Since UNIX drivers are 73*30380Smckusick * not capable of scheduling multi-block transfers, this defaults 74*30380Smckusick * to 1 (ie no contiguous blocks are allocated). 75*30380Smckusick */ 76*30380Smckusick #define MAXCONTIG 1 77*30380Smckusick 78*30380Smckusick /* 79*30380Smckusick * Each file system has a number of inodes statically allocated. 80*30380Smckusick * We allocate one inode slot per NBPI bytes, expecting this 81*30380Smckusick * to be far more than we will ever need. 82*30380Smckusick */ 83*30380Smckusick #define NBPI 2048 84*30380Smckusick 85*30380Smckusick int Nflag; /* run without writing file system */ 8610762Ssam int fssize; /* file system size */ 8710762Ssam int ntracks; /* # tracks/cylinder */ 8810762Ssam int nsectors; /* # sectors/track */ 89*30380Smckusick int nspares = -1; /* spare sectors per cylinder */ 90*30380Smckusick int secpercyl; /* sectors per cylinder */ 9110762Ssam int sectorsize; /* bytes/sector */ 9211069Ssam int rpm; /* revolutions/minute of drive */ 93*30380Smckusick int fsize = DFL_FRAGSIZE; /* fragment size */ 94*30380Smckusick int bsize = DFL_BLKSIZE; /* block size */ 95*30380Smckusick int cpg = DESCPG; /* cylinders/cylinder group */ 96*30380Smckusick int minfree = MINFREE; /* free space threshold */ 97*30380Smckusick int opt = DEFAULTOPT; /* optimization preference (space or time) */ 98*30380Smckusick int density = NBPI; /* number of bytes per inode */ 99*30380Smckusick int maxcontig = MAXCONTIG; /* max contiguous blocks to allocate */ 100*30380Smckusick int rotdelay = ROTDELAY; /* rotational delay between blocks */ 10110762Ssam 10210762Ssam char device[MAXPATHLEN]; 10310762Ssam 104*30380Smckusick extern int errno; 10510762Ssam char *index(); 10610762Ssam char *rindex(); 10710762Ssam char *sprintf(); 10810762Ssam 10910762Ssam main(argc, argv) 11014064Smckusick int argc; 11110762Ssam char *argv[]; 11210762Ssam { 11310762Ssam char *cp, *special; 11410762Ssam register struct partition *pp; 115*30380Smckusick register struct disklabel *lp; 116*30380Smckusick struct disklabel *getdisklabel(); 117*30380Smckusick struct partition oldpartition; 11810762Ssam struct stat st; 119*30380Smckusick int fsi, fso; 12010762Ssam register int i; 12110762Ssam int status; 12210762Ssam 12310762Ssam argc--, argv++; 12410762Ssam while (argc > 0 && argv[0][0] == '-') { 12510762Ssam for (cp = &argv[0][1]; *cp; cp++) 12610762Ssam switch (*cp) { 12710762Ssam 12816945Smckusick case 'N': 12916945Smckusick Nflag++; 13012334Shelge break; 13112334Shelge 132*30380Smckusick case 'S': 13310762Ssam if (argc < 1) 134*30380Smckusick fatal("-S: missing sector size"); 13510762Ssam argc--, argv++; 136*30380Smckusick sectorsize = atoi(*argv); 137*30380Smckusick if (sectorsize <= 0) 138*30380Smckusick fatal("%s: bad sector size", *argv); 13910762Ssam goto next; 14010762Ssam 141*30380Smckusick case 'a': 14210762Ssam if (argc < 1) 143*30380Smckusick fatal("-a: spare sectors per cylinder"); 14410762Ssam argc--, argv++; 145*30380Smckusick nspares = atoi(*argv); 146*30380Smckusick if (nspares < 0) 147*30380Smckusick fatal("%s: bad spare sectors per cylinder", *argv); 14810762Ssam goto next; 14910762Ssam 15010762Ssam case 'b': 15110762Ssam if (argc < 1) 15210762Ssam fatal("-b: missing block size"); 15310762Ssam argc--, argv++; 15410762Ssam bsize = atoi(*argv); 155*30380Smckusick if (bsize < MINBSIZE) 15610762Ssam fatal("%s: bad block size", *argv); 15710762Ssam goto next; 15810762Ssam 159*30380Smckusick case 'c': 160*30380Smckusick if (argc < 1) 161*30380Smckusick fatal("-c: missing cylinders/group"); 162*30380Smckusick argc--, argv++; 163*30380Smckusick cpg = atoi(*argv); 164*30380Smckusick if (cpg <= 0) 165*30380Smckusick fatal("%s: bad cylinders/group", *argv); 166*30380Smckusick goto next; 167*30380Smckusick 168*30380Smckusick case 'd': 169*30380Smckusick if (argc < 1) 170*30380Smckusick fatal("-d: missing sectors/track"); 171*30380Smckusick argc--, argv++; 172*30380Smckusick nsectors = atoi(*argv); 173*30380Smckusick if (nsectors <= 0) 174*30380Smckusick fatal("%s: bad sectors/track", *argv); 175*30380Smckusick goto next; 176*30380Smckusick 17710762Ssam case 'f': 17810762Ssam if (argc < 1) 17910762Ssam fatal("-f: missing frag size"); 18010762Ssam argc--, argv++; 18110762Ssam fsize = atoi(*argv); 182*30380Smckusick if (fsize <= 0) 18310762Ssam fatal("%s: bad frag size", *argv); 18410762Ssam goto next; 18510762Ssam 186*30380Smckusick case 'i': 18710762Ssam if (argc < 1) 188*30380Smckusick fatal("-i: missing bytes per inode\n"); 18910762Ssam argc--, argv++; 190*30380Smckusick density = atoi(*argv); 191*30380Smckusick if (density <= 0) 192*30380Smckusick fatal("%s: bad bytes per inode\n", 193*30380Smckusick *argv); 19410762Ssam goto next; 19510762Ssam 19611069Ssam case 'm': 19711069Ssam if (argc < 1) 19811069Ssam fatal("-m: missing free space %%\n"); 19911069Ssam argc--, argv++; 20011069Ssam minfree = atoi(*argv); 20111069Ssam if (minfree < 0 || minfree > 99) 20211069Ssam fatal("%s: bad free space %%\n", 20311069Ssam *argv); 20411069Ssam goto next; 20511069Ssam 206*30380Smckusick case 'o': 207*30380Smckusick if (argc < 1) 208*30380Smckusick fatal("-o: missing optimization preference"); 209*30380Smckusick argc--, argv++; 210*30380Smckusick if (strcmp(*argv, "space") == 0) 211*30380Smckusick opt = FS_OPTSPACE; 212*30380Smckusick else if (strcmp(*argv, "time") == 0) 213*30380Smckusick opt = FS_OPTTIME; 214*30380Smckusick else 215*30380Smckusick fatal("%s: bad optimization preference %s", 216*30380Smckusick *argv, 217*30380Smckusick "(options are `space' or `time')"); 218*30380Smckusick goto next; 219*30380Smckusick 22011069Ssam case 'r': 22111069Ssam if (argc < 1) 22211069Ssam fatal("-r: missing revs/minute\n"); 22311069Ssam argc--, argv++; 22411069Ssam rpm = atoi(*argv); 225*30380Smckusick if (rpm <= 0) 22611069Ssam fatal("%s: bad revs/minute\n", *argv); 22711069Ssam goto next; 22811069Ssam 229*30380Smckusick case 's': 23014884Smckusick if (argc < 1) 231*30380Smckusick fatal("-s: missing file system size"); 23214884Smckusick argc--, argv++; 233*30380Smckusick fssize = atoi(*argv); 234*30380Smckusick if (fssize <= 0) 235*30380Smckusick fatal("%s: bad file system size", 23614884Smckusick *argv); 23714884Smckusick goto next; 23814884Smckusick 239*30380Smckusick case 't': 240*30380Smckusick if (argc < 1) 241*30380Smckusick fatal("-t: missing track total"); 242*30380Smckusick argc--, argv++; 243*30380Smckusick ntracks = atoi(*argv); 244*30380Smckusick if (ntracks <= 0) 245*30380Smckusick fatal("%s: bad total tracks", *argv); 246*30380Smckusick goto next; 247*30380Smckusick 24810762Ssam default: 24910762Ssam fatal("-%c: unknown flag", cp); 25010762Ssam } 25110762Ssam next: 25210762Ssam argc--, argv++; 25310762Ssam } 254*30380Smckusick if (argc < 1) { 255*30380Smckusick fprintf(stderr, "usage: newfs [ fsoptions ] special-device\n"); 256*30380Smckusick fprintf(stderr, "where fsoptions are:\n"); 25716945Smckusick fprintf(stderr, "\t-N do not create file system, %s\n", 25816945Smckusick "just print out parameters"); 25911057Ssam fprintf(stderr, "\t-s file system size (sectors)\n"); 26011057Ssam fprintf(stderr, "\t-b block size\n"); 26111057Ssam fprintf(stderr, "\t-f frag size\n"); 262*30380Smckusick fprintf(stderr, "\t-d sectors/track\n"); 26310873Ssam fprintf(stderr, "\t-t tracks/cylinder\n"); 26410873Ssam fprintf(stderr, "\t-c cylinders/group\n"); 26511069Ssam fprintf(stderr, "\t-m minimum free space %%\n"); 26624702Smckusick fprintf(stderr, "\t-o optimization preference %s\n", 26724702Smckusick "(`space' or `time')"); 26811069Ssam fprintf(stderr, "\t-r revolutions/minute\n"); 269*30380Smckusick fprintf(stderr, "\t-i number of bytes per inode\n"); 27011057Ssam fprintf(stderr, "\t-S sector size\n"); 271*30380Smckusick fprintf(stderr, "\t-a spare sectors per cylinder\n"); 27210762Ssam exit(1); 27310762Ssam } 27410762Ssam special = argv[0]; 27514064Smckusick cp = rindex(special, '/'); 27614064Smckusick if (cp != 0) 27714064Smckusick special = cp + 1; 27814321Ssam if (*special == 'r' && special[1] != 'a' && special[1] != 'b') 27914064Smckusick special++; 28014064Smckusick special = sprintf(device, "/dev/r%s", special); 281*30380Smckusick if (!Nflag) { 282*30380Smckusick fso = open(special, O_WRONLY); 283*30380Smckusick if (fso < 0) { 284*30380Smckusick perror(special); 285*30380Smckusick exit(1); 286*30380Smckusick } 287*30380Smckusick } else 288*30380Smckusick fso = -1; 289*30380Smckusick fsi = open(special, O_RDONLY); 290*30380Smckusick if (fsi < 0) { 291*30380Smckusick perror(special); 292*30380Smckusick exit(1); 293*30380Smckusick } 294*30380Smckusick if (fstat(fsi, &st) < 0) { 29511069Ssam fprintf(stderr, "newfs: "); perror(special); 29610762Ssam exit(2); 29710762Ssam } 29814064Smckusick if ((st.st_mode & S_IFMT) != S_IFCHR) 29914064Smckusick fatal("%s: not a character device", special); 30010762Ssam cp = index(argv[0], '\0') - 1; 301*30380Smckusick if (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) 30210762Ssam fatal("%s: can't figure out file system partition", argv[0]); 303*30380Smckusick lp = getdisklabel(special, fsi); 304*30380Smckusick if (isdigit(*cp)) 305*30380Smckusick pp = &lp->d_partitions[0]; 306*30380Smckusick else 307*30380Smckusick pp = &lp->d_partitions[*cp - 'a']; 308*30380Smckusick if (pp->p_size == 0) 309*30380Smckusick fatal("%s: `%c' partition is unavailable", argv[0], *cp); 310*30380Smckusick if (fssize == 0) 31110762Ssam fssize = pp->p_size; 312*30380Smckusick if (fssize > pp->p_size) 313*30380Smckusick fatal("%s: maximum file system size on the `%c' partition is %d", 314*30380Smckusick argv[0], *cp, pp->p_size); 315*30380Smckusick if (rpm == 0) { 316*30380Smckusick rpm = lp->d_rpm; 317*30380Smckusick if (rpm <= 0) 318*30380Smckusick fatal("%s: no default rpm", argv[1]); 31910762Ssam } 320*30380Smckusick if (ntracks == 0) { 321*30380Smckusick ntracks = lp->d_ntracks; 322*30380Smckusick if (ntracks <= 0) 323*30380Smckusick fatal("%s: no default #tracks", argv[1]); 324*30380Smckusick } 32510762Ssam if (nsectors == 0) { 326*30380Smckusick nsectors = lp->d_nsectors; 327*30380Smckusick if (nsectors <= 0) 32810762Ssam fatal("%s: no default #sectors/track", argv[1]); 32910762Ssam } 33010762Ssam if (sectorsize == 0) { 331*30380Smckusick sectorsize = lp->d_secsize; 332*30380Smckusick if (sectorsize <= 0) 33310762Ssam fatal("%s: no default sector size", argv[1]); 33410762Ssam } 33510762Ssam if (fsize == 0) { 33610762Ssam fsize = pp->p_fsize; 337*30380Smckusick if (fsize <= 0) 338*30380Smckusick fsize = MAX(DFL_FRAGSIZE, lp->d_secsize); 33910762Ssam } 340*30380Smckusick if (bsize == 0) { 341*30380Smckusick bsize = pp->p_frag * pp->p_fsize; 342*30380Smckusick if (bsize <= 0) 343*30380Smckusick bsize = MIN(DFL_BLKSIZE, 8 * fsize); 34411069Ssam } 34524702Smckusick if (minfree < 10 && opt != FS_OPTSPACE) { 346*30380Smckusick fprintf(stderr, "Warning: changing optimization to space "); 347*30380Smckusick fprintf(stderr, "because minfree is less than 10%%\n"); 34824702Smckusick opt = FS_OPTSPACE; 34924702Smckusick } 350*30380Smckusick if (nspares == -1) 351*30380Smckusick nspares = lp->d_sparespercyl; 352*30380Smckusick secpercyl = nsectors * ntracks - nspares; 353*30380Smckusick if (secpercyl != lp->d_secpercyl) 354*30380Smckusick fprintf(stderr, "%s (%d) %s (%d)\n", 355*30380Smckusick "Warning: calculated sectors per cylinder", secpercyl, 356*30380Smckusick "disagrees with disk label", lp->d_secpercyl); 357*30380Smckusick oldpartition = *pp; 358*30380Smckusick mkfs(pp, special, fsi, fso); 359*30380Smckusick if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition))) 360*30380Smckusick rewritelabel(special, fso, lp); 361*30380Smckusick exit(0); 362*30380Smckusick } 363*30380Smckusick 364*30380Smckusick #ifdef byioctl 365*30380Smckusick struct disklabel * 366*30380Smckusick getdisklabel(s, fd) 367*30380Smckusick char *s; 368*30380Smckusick int fd; 369*30380Smckusick { 370*30380Smckusick static struct disklabel lab; 371*30380Smckusick 372*30380Smckusick if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { 373*30380Smckusick perror("ioctl (GDINFO)"); 374*30380Smckusick fatal("%s: can't read disk label", s); 37510762Ssam } 376*30380Smckusick return (&lab); 377*30380Smckusick } 37810762Ssam 379*30380Smckusick rewritelabel(s, fd, lp) 380*30380Smckusick char *s; 381*30380Smckusick int fd; 382*30380Smckusick register struct disklabel *lp; 383*30380Smckusick { 384*30380Smckusick 385*30380Smckusick lp->d_checksum = 0; 386*30380Smckusick lp->d_checksum = dkcksum(lp); 387*30380Smckusick if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { 388*30380Smckusick perror("ioctl (GWINFO)"); 389*30380Smckusick fatal("%s: can't rewrite disk label", s); 39010762Ssam } 39110762Ssam } 392*30380Smckusick #else byioctl 393*30380Smckusick char specname[64]; 394*30380Smckusick char boot[BBSIZE]; 39510762Ssam 396*30380Smckusick struct disklabel * 397*30380Smckusick getdisklabel(s, fd) 398*30380Smckusick char *s; 399*30380Smckusick int fd; 40010762Ssam { 401*30380Smckusick char *cp; 402*30380Smckusick u_long magic = htonl(DISKMAGIC); 403*30380Smckusick register struct disklabel *lp; 404*30380Smckusick int cfd; 40510762Ssam 406*30380Smckusick /* 407*30380Smckusick * Make name for 'c' partition. 408*30380Smckusick */ 409*30380Smckusick strcpy(specname, s); 410*30380Smckusick cp = specname + strlen(specname) - 1; 411*30380Smckusick if (!isdigit(*cp)) 412*30380Smckusick *cp = 'c'; 413*30380Smckusick cfd = open(specname, O_RDONLY); 414*30380Smckusick if (cfd < 0) { 415*30380Smckusick perror(specname); 416*30380Smckusick exit(2); 41710762Ssam } 418*30380Smckusick 419*30380Smckusick if (read(cfd, boot, BBSIZE) < BBSIZE) { 420*30380Smckusick perror(specname); 42110762Ssam exit(2); 42210762Ssam } 423*30380Smckusick close(cfd); 424*30380Smckusick for (lp = (struct disklabel *)(boot + LABELOFFSET); 425*30380Smckusick lp <= (struct disklabel *)(boot + BBSIZE - 426*30380Smckusick sizeof(struct disklabel)); 427*30380Smckusick lp = (struct disklabel *)((char *)lp + 128)) 428*30380Smckusick if (lp->d_magic == magic && lp->d_magic2 == magic) 429*30380Smckusick break; 430*30380Smckusick if (lp > (struct disklabel *)(boot + BBSIZE - 431*30380Smckusick sizeof(struct disklabel)) || 432*30380Smckusick lp->d_magic != magic || lp->d_magic2 != magic || 433*30380Smckusick dkcksum(lp) != 0) { 434*30380Smckusick fprintf(stderr, 435*30380Smckusick "Bad pack magic number (label is damaged, or pack is unlabeled)\n"); 43610762Ssam exit(1); 43710762Ssam } 438*30380Smckusick #if ENDIAN != BIG 439*30380Smckusick swablabel(lp); 440*30380Smckusick #endif 441*30380Smckusick return (lp); 442*30380Smckusick } 443*30380Smckusick 444*30380Smckusick rewritelabel(s, fd, lp) 445*30380Smckusick char *s; 446*30380Smckusick int fd; 447*30380Smckusick register struct disklabel *lp; 448*30380Smckusick { 449*30380Smckusick daddr_t alt; 450*30380Smckusick register i; 451*30380Smckusick int secsize, cfd; 452*30380Smckusick 453*30380Smckusick secsize = lp->d_secsize; 454*30380Smckusick alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 455*30380Smckusick #if ENDIAN != BIG 456*30380Smckusick swablabel(lp); 457*30380Smckusick #endif 458*30380Smckusick lp->d_checksum = 0; 459*30380Smckusick lp->d_checksum = dkcksum(lp); 460*30380Smckusick cfd = open(specname, O_WRONLY); 461*30380Smckusick if (cfd < 0) { 462*30380Smckusick perror(specname); 46310762Ssam exit(2); 46410762Ssam } 465*30380Smckusick lseek(cfd, (off_t)0, L_SET); 466*30380Smckusick if (write(cfd, boot, BBSIZE) < BBSIZE) { 467*30380Smckusick perror(specname); 46810762Ssam exit(2); 46910762Ssam } 470*30380Smckusick for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 471*30380Smckusick lseek(cfd, (off_t)(alt + i) * secsize, L_SET); 472*30380Smckusick if (write(cfd, boot, secsize) < secsize) { 473*30380Smckusick int oerrno = errno; 474*30380Smckusick fprintf(stderr, "alternate label %d ", i/2); 475*30380Smckusick errno = oerrno; 476*30380Smckusick perror("write"); 477*30380Smckusick } 478*30380Smckusick } 479*30380Smckusick close(cfd); 48010762Ssam } 481*30380Smckusick #endif byioctl 48210762Ssam 48310762Ssam /*VARARGS*/ 48410762Ssam fatal(fmt, arg1, arg2) 48510762Ssam char *fmt; 48610762Ssam { 48710762Ssam 48811069Ssam fprintf(stderr, "newfs: "); 48910762Ssam fprintf(stderr, fmt, arg1, arg2); 49010762Ssam putc('\n', stderr); 49110762Ssam exit(10); 49210762Ssam } 493