mkfs.c revision 92710
1/* 2 * Copyright (c) 1980, 1989, 1993 3 * The Regents of the University of California. 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#if 0 36static char sccsid[] = "@(#)mkfs.c 8.11 (Berkeley) 5/3/95"; 37#endif 38static const char rcsid[] = 39 "$FreeBSD: head/sbin/newfs/mkfs.c 92710 2002-03-19 17:03:14Z iedowse $"; 40#endif /* not lint */ 41 42#include <err.h> 43#include <signal.h> 44#include <stdlib.h> 45#include <string.h> 46#include <stdio.h> 47#include <unistd.h> 48#include <sys/param.h> 49#include <sys/time.h> 50#include <sys/types.h> 51#include <sys/wait.h> 52#include <sys/resource.h> 53#include <sys/stat.h> 54#include <ufs/ufs/dinode.h> 55#include <ufs/ufs/dir.h> 56#include <ufs/ffs/fs.h> 57#include <sys/disklabel.h> 58#include <sys/file.h> 59#include <sys/mman.h> 60#include <sys/ioctl.h> 61 62/* 63 * make file system for cylinder-group style file systems 64 */ 65 66/* 67 * We limit the size of the inode map to be no more than a 68 * third of the cylinder group space, since we must leave at 69 * least an equal amount of space for the block map. 70 * 71 * N.B.: MAXIPG must be a multiple of INOPB(fs). 72 */ 73#define MAXIPG(fs) roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs)) 74 75#define UMASK 0755 76#define MAXINOPB (MAXBSIZE / sizeof(struct dinode)) 77#define POWEROF2(num) (((num) & ((num) - 1)) == 0) 78 79/* 80 * variables set up by front end. 81 */ 82extern int Nflag; /* run mkfs without writing file system */ 83extern int Oflag; /* format as an 4.3BSD file system */ 84extern int Uflag; /* enable soft updates for file system */ 85extern int fssize; /* file system size */ 86extern int ntracks; /* # tracks/cylinder */ 87extern int nsectors; /* # sectors/track */ 88extern int nphyssectors; /* # sectors/track including spares */ 89extern int secpercyl; /* sectors per cylinder */ 90extern int sectorsize; /* bytes/sector */ 91extern int realsectorsize; /* bytes/sector in hardware*/ 92extern int rpm; /* revolutions/minute of drive */ 93extern int interleave; /* hardware sector interleave */ 94extern int trackskew; /* sector 0 skew, per track */ 95extern int fsize; /* fragment size */ 96extern int bsize; /* block size */ 97extern int cpg; /* cylinders/cylinder group */ 98extern int cpgflg; /* cylinders/cylinder group flag was given */ 99extern int minfree; /* free space threshold */ 100extern int opt; /* optimization preference (space or time) */ 101extern int density; /* number of bytes per inode */ 102extern int maxcontig; /* max contiguous blocks to allocate */ 103extern int rotdelay; /* rotational delay between blocks */ 104extern int maxbpg; /* maximum blocks per file in a cyl group */ 105extern int nrpos; /* # of distinguished rotational positions */ 106extern int bbsize; /* boot block size */ 107extern int sbsize; /* superblock size */ 108extern int avgfilesize; /* expected average file size */ 109extern int avgfilesperdir; /* expected number of files per directory */ 110 111union { 112 struct fs fs; 113 char pad[SBSIZE]; 114} fsun; 115#define sblock fsun.fs 116struct csum *fscs; 117 118union { 119 struct cg cg; 120 char pad[MAXBSIZE]; 121} cgun; 122#define acg cgun.cg 123 124struct dinode zino[MAXBSIZE / sizeof(struct dinode)]; 125 126int fsi, fso; 127int randinit; 128daddr_t alloc(); 129long calcipg(); 130static int charsperline(); 131void clrblock (struct fs *, unsigned char *, int); 132void fsinit (time_t); 133void initcg (int, time_t); 134int isblock (struct fs *, unsigned char *, int); 135void iput (struct dinode *, ino_t); 136int makedir (struct direct *, int); 137void rdfs (daddr_t, int, char *); 138void setblock (struct fs *, unsigned char *, int); 139void wtfs (daddr_t, int, char *); 140void wtfsflush (void); 141 142void 143mkfs(pp, fsys, fi, fo) 144 struct partition *pp; 145 char *fsys; 146 int fi, fo; 147{ 148 long i, mincpc, mincpg, inospercg; 149 long cylno, rpos, blk, j, warn = 0; 150 long used, mincpgcnt, bpcg; 151 off_t usedb; 152 long mapcramped, inodecramped; 153 long postblsize, rotblsize, totalsbsize; 154 time_t utime; 155 quad_t sizepb; 156 int width; 157 char tmpbuf[100]; /* XXX this will break in about 2,500 years */ 158 159 time(&utime); 160 if (!randinit) { 161 randinit = 1; 162 srandomdev(); 163 } 164 fsi = fi; 165 fso = fo; 166 if (Oflag) { 167 sblock.fs_inodefmt = FS_42INODEFMT; 168 sblock.fs_maxsymlinklen = 0; 169 } else { 170 sblock.fs_inodefmt = FS_44INODEFMT; 171 sblock.fs_maxsymlinklen = MAXSYMLINKLEN; 172 } 173 if (Uflag) 174 sblock.fs_flags |= FS_DOSOFTDEP; 175 /* 176 * Validate the given file system size. 177 * Verify that its last block can actually be accessed. 178 */ 179 if (fssize <= 0) 180 printf("preposterous size %d\n", fssize), exit(13); 181 wtfs(fssize - (realsectorsize / DEV_BSIZE), realsectorsize, 182 (char *)&sblock); 183 /* 184 * collect and verify the sector and track info 185 */ 186 sblock.fs_nsect = nsectors; 187 sblock.fs_ntrak = ntracks; 188 if (sblock.fs_ntrak <= 0) 189 printf("preposterous ntrak %d\n", sblock.fs_ntrak), exit(14); 190 if (sblock.fs_nsect <= 0) 191 printf("preposterous nsect %d\n", sblock.fs_nsect), exit(15); 192 /* 193 * collect and verify the filesystem density info 194 */ 195 sblock.fs_avgfilesize = avgfilesize; 196 sblock.fs_avgfpdir = avgfilesperdir; 197 if (sblock.fs_avgfilesize <= 0) 198 printf("illegal expected average file size %d\n", 199 sblock.fs_avgfilesize), exit(14); 200 if (sblock.fs_avgfpdir <= 0) 201 printf("illegal expected number of files per directory %d\n", 202 sblock.fs_avgfpdir), exit(15); 203 /* 204 * collect and verify the block and fragment sizes 205 */ 206 sblock.fs_bsize = bsize; 207 sblock.fs_fsize = fsize; 208 if (!POWEROF2(sblock.fs_bsize)) { 209 printf("block size must be a power of 2, not %d\n", 210 sblock.fs_bsize); 211 exit(16); 212 } 213 if (!POWEROF2(sblock.fs_fsize)) { 214 printf("fragment size must be a power of 2, not %d\n", 215 sblock.fs_fsize); 216 exit(17); 217 } 218 if (sblock.fs_fsize < sectorsize) { 219 printf("fragment size %d is too small, minimum is %d\n", 220 sblock.fs_fsize, sectorsize); 221 exit(18); 222 } 223 if (sblock.fs_bsize < MINBSIZE) { 224 printf("block size %d is too small, minimum is %d\n", 225 sblock.fs_bsize, MINBSIZE); 226 exit(19); 227 } 228 if (sblock.fs_bsize < sblock.fs_fsize) { 229 printf( 230 "block size (%d) cannot be smaller than fragment size (%d)\n", 231 sblock.fs_bsize, sblock.fs_fsize); 232 exit(20); 233 } 234 sblock.fs_bmask = ~(sblock.fs_bsize - 1); 235 sblock.fs_fmask = ~(sblock.fs_fsize - 1); 236 sblock.fs_qbmask = ~sblock.fs_bmask; 237 sblock.fs_qfmask = ~sblock.fs_fmask; 238 for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1) 239 sblock.fs_bshift++; 240 for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1) 241 sblock.fs_fshift++; 242 sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); 243 for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1) 244 sblock.fs_fragshift++; 245 if (sblock.fs_frag > MAXFRAG) { 246 printf( 247 "fragment size %d is too small, minimum with block size %d is %d\n", 248 sblock.fs_fsize, sblock.fs_bsize, 249 sblock.fs_bsize / MAXFRAG); 250 exit(21); 251 } 252 sblock.fs_nrpos = nrpos; 253 sblock.fs_nindir = sblock.fs_bsize / sizeof(daddr_t); 254 sblock.fs_inopb = sblock.fs_bsize / sizeof(struct dinode); 255 sblock.fs_nspf = sblock.fs_fsize / sectorsize; 256 for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1) 257 sblock.fs_fsbtodb++; 258 sblock.fs_sblkno = 259 roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag); 260 sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno + 261 roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag)); 262 sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; 263 sblock.fs_cgoffset = 264 roundup(howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag); 265 for (sblock.fs_cgmask = 0xffffffff, i = sblock.fs_ntrak; i > 1; i >>= 1) 266 sblock.fs_cgmask <<= 1; 267 if (!POWEROF2(sblock.fs_ntrak)) 268 sblock.fs_cgmask <<= 1; 269 sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; 270 for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) { 271 sizepb *= NINDIR(&sblock); 272 sblock.fs_maxfilesize += sizepb; 273 } 274 /* 275 * Validate specified/determined secpercyl 276 * and calculate minimum cylinders per group. 277 */ 278 sblock.fs_spc = secpercyl; 279 for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc; 280 sblock.fs_cpc > 1 && (i & 1) == 0; 281 sblock.fs_cpc >>= 1, i >>= 1) 282 /* void */; 283 mincpc = sblock.fs_cpc; 284 bpcg = sblock.fs_spc * sectorsize; 285 inospercg = roundup(bpcg / sizeof(struct dinode), INOPB(&sblock)); 286 if (inospercg > MAXIPG(&sblock)) 287 inospercg = MAXIPG(&sblock); 288 used = (sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock); 289 mincpgcnt = howmany(sblock.fs_cgoffset * (~sblock.fs_cgmask) + used, 290 sblock.fs_spc); 291 mincpg = roundup(mincpgcnt, mincpc); 292 /* 293 * Ensure that cylinder group with mincpg has enough space 294 * for block maps. 295 */ 296 sblock.fs_cpg = mincpg; 297 sblock.fs_ipg = inospercg; 298 if (maxcontig > 1) 299 sblock.fs_contigsumsize = MIN(maxcontig, FS_MAXCONTIG); 300 mapcramped = 0; 301 while (CGSIZE(&sblock) > sblock.fs_bsize) { 302 mapcramped = 1; 303 if (sblock.fs_bsize < MAXBSIZE) { 304 sblock.fs_bsize <<= 1; 305 if ((i & 1) == 0) 306 i >>= 1; 307 else { 308 sblock.fs_cpc <<= 1; 309 mincpc <<= 1; 310 mincpg = roundup(mincpgcnt, mincpc); 311 sblock.fs_cpg = mincpg; 312 } 313 sblock.fs_frag <<= 1; 314 sblock.fs_fragshift += 1; 315 if (sblock.fs_frag <= MAXFRAG) 316 continue; 317 } 318 if (sblock.fs_fsize == sblock.fs_bsize) { 319 printf("There is no block size that"); 320 printf(" can support this disk\n"); 321 exit(22); 322 } 323 sblock.fs_frag >>= 1; 324 sblock.fs_fragshift -= 1; 325 sblock.fs_fsize <<= 1; 326 sblock.fs_nspf <<= 1; 327 } 328 /* 329 * Ensure that cylinder group with mincpg has enough space for inodes. 330 */ 331 inodecramped = 0; 332 inospercg = calcipg(mincpg, bpcg, &usedb); 333 sblock.fs_ipg = inospercg; 334 while (inospercg > MAXIPG(&sblock)) { 335 inodecramped = 1; 336 if (mincpc == 1 || sblock.fs_frag == 1 || 337 sblock.fs_bsize == MINBSIZE) 338 break; 339 printf("With a block size of %d %s %d\n", sblock.fs_bsize, 340 "minimum bytes per inode is", 341 (int)((mincpg * (off_t)bpcg - usedb) / 342 MAXIPG(&sblock) + 1)); 343 sblock.fs_bsize >>= 1; 344 sblock.fs_frag >>= 1; 345 sblock.fs_fragshift -= 1; 346 mincpc >>= 1; 347 sblock.fs_cpg = roundup(mincpgcnt, mincpc); 348 if (CGSIZE(&sblock) > sblock.fs_bsize) { 349 sblock.fs_bsize <<= 1; 350 break; 351 } 352 mincpg = sblock.fs_cpg; 353 inospercg = calcipg(mincpg, bpcg, &usedb); 354 sblock.fs_ipg = inospercg; 355 } 356 if (inodecramped) { 357 if (inospercg > MAXIPG(&sblock)) { 358 printf("Minimum bytes per inode is %d\n", 359 (int)((mincpg * (off_t)bpcg - usedb) / 360 MAXIPG(&sblock) + 1)); 361 } else if (!mapcramped) { 362 printf("With %d bytes per inode, ", density); 363 printf("minimum cylinders per group is %ld\n", mincpg); 364 } 365 } 366 if (mapcramped) { 367 printf("With %d sectors per cylinder, ", sblock.fs_spc); 368 printf("minimum cylinders per group is %ld\n", mincpg); 369 } 370 if (inodecramped || mapcramped) { 371 if (sblock.fs_bsize != bsize) 372 printf("%s to be changed from %d to %d\n", 373 "This requires the block size", 374 bsize, sblock.fs_bsize); 375 if (sblock.fs_fsize != fsize) 376 printf("\t%s to be changed from %d to %d\n", 377 "and the fragment size", fsize, sblock.fs_fsize); 378 exit(23); 379 } 380 /* 381 * Calculate the number of cylinders per group 382 */ 383 sblock.fs_cpg = cpg; 384 if (sblock.fs_cpg % mincpc != 0) { 385 printf("%s groups must have a multiple of %ld cylinders\n", 386 cpgflg ? "Cylinder" : "Warning: cylinder", mincpc); 387 sblock.fs_cpg = roundup(sblock.fs_cpg, mincpc); 388 if (!cpgflg) 389 cpg = sblock.fs_cpg; 390 } 391 /* 392 * Must ensure there is enough space for inodes. 393 */ 394 sblock.fs_ipg = calcipg(sblock.fs_cpg, bpcg, &usedb); 395 while (sblock.fs_ipg > MAXIPG(&sblock)) { 396 inodecramped = 1; 397 sblock.fs_cpg -= mincpc; 398 sblock.fs_ipg = calcipg(sblock.fs_cpg, bpcg, &usedb); 399 } 400 /* 401 * Must ensure there is enough space to hold block map. 402 */ 403 while (CGSIZE(&sblock) > sblock.fs_bsize) { 404 mapcramped = 1; 405 sblock.fs_cpg -= mincpc; 406 sblock.fs_ipg = calcipg(sblock.fs_cpg, bpcg, &usedb); 407 } 408 sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock); 409 if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) { 410 printf("panic (fs_cpg * fs_spc) %% NSPF != 0"); 411 exit(24); 412 } 413 if (sblock.fs_cpg < mincpg) { 414 printf("cylinder groups must have at least %ld cylinders\n", 415 mincpg); 416 exit(25); 417 } else if (sblock.fs_cpg != cpg) { 418 if (!cpgflg) 419 printf("Warning: "); 420 else if (!mapcramped && !inodecramped) 421 exit(26); 422 if (mapcramped && inodecramped) 423 printf("Block size and bytes per inode restrict"); 424 else if (mapcramped) 425 printf("Block size restricts"); 426 else 427 printf("Bytes per inode restrict"); 428 printf(" cylinders per group to %d.\n", sblock.fs_cpg); 429 if (cpgflg) 430 exit(27); 431 } 432 sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); 433 /* 434 * Now have size for file system and nsect and ntrak. 435 * Determine number of cylinders and blocks in the file system. 436 */ 437 sblock.fs_size = fssize = dbtofsb(&sblock, fssize); 438 sblock.fs_ncyl = fssize * NSPF(&sblock) / sblock.fs_spc; 439 if (fssize * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) { 440 sblock.fs_ncyl++; 441 warn = 1; 442 } 443 if (sblock.fs_ncyl < 1) { 444 printf("file systems must have at least one cylinder\n"); 445 exit(28); 446 } 447 /* 448 * Determine feasability/values of rotational layout tables. 449 * 450 * The size of the rotational layout tables is limited by the 451 * size of the superblock, SBSIZE. The amount of space available 452 * for tables is calculated as (SBSIZE - sizeof (struct fs)). 453 * The size of these tables is inversely proportional to the block 454 * size of the file system. The size increases if sectors per track 455 * are not powers of two, because more cylinders must be described 456 * by the tables before the rotational pattern repeats (fs_cpc). 457 */ 458 sblock.fs_interleave = interleave; 459 sblock.fs_trackskew = trackskew; 460 sblock.fs_npsect = nphyssectors; 461 sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT; 462 sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs)); 463 if (sblock.fs_sbsize > SBSIZE) 464 sblock.fs_sbsize = SBSIZE; 465 if (sblock.fs_ntrak == 1) { 466 sblock.fs_cpc = 0; 467 goto next; 468 } 469 postblsize = sblock.fs_nrpos * sblock.fs_cpc * sizeof(int16_t); 470 rotblsize = sblock.fs_cpc * sblock.fs_spc / NSPB(&sblock); 471 totalsbsize = sizeof(struct fs) + rotblsize; 472 if (sblock.fs_nrpos == 8 && sblock.fs_cpc <= 16) { 473 /* use old static table space */ 474 sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) - 475 (char *)(&sblock.fs_firstfield); 476 sblock.fs_rotbloff = &sblock.fs_space[0] - 477 (u_char *)(&sblock.fs_firstfield); 478 } else { 479 /* use dynamic table space */ 480 sblock.fs_postbloff = &sblock.fs_space[0] - 481 (u_char *)(&sblock.fs_firstfield); 482 sblock.fs_rotbloff = sblock.fs_postbloff + postblsize; 483 totalsbsize += postblsize; 484 } 485 if (totalsbsize > SBSIZE || 486 sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) { 487 printf("%s %s %d %s %d.%s", 488 "Warning: insufficient space in super block for\n", 489 "rotational layout tables with nsect", sblock.fs_nsect, 490 "and ntrak", sblock.fs_ntrak, 491 "\nFile system performance may be impaired.\n"); 492 sblock.fs_cpc = 0; 493 goto next; 494 } 495 sblock.fs_sbsize = fragroundup(&sblock, totalsbsize); 496 if (sblock.fs_sbsize > SBSIZE) 497 sblock.fs_sbsize = SBSIZE; 498 /* 499 * calculate the available blocks for each rotational position 500 */ 501 for (cylno = 0; cylno < sblock.fs_cpc; cylno++) 502 for (rpos = 0; rpos < sblock.fs_nrpos; rpos++) 503 fs_postbl(&sblock, cylno)[rpos] = -1; 504 for (i = (rotblsize - 1) * sblock.fs_frag; 505 i >= 0; i -= sblock.fs_frag) { 506 cylno = cbtocylno(&sblock, i); 507 rpos = cbtorpos(&sblock, i); 508 blk = fragstoblks(&sblock, i); 509 if (fs_postbl(&sblock, cylno)[rpos] == -1) 510 fs_rotbl(&sblock)[blk] = 0; 511 else 512 fs_rotbl(&sblock)[blk] = 513 fs_postbl(&sblock, cylno)[rpos] - blk; 514 fs_postbl(&sblock, cylno)[rpos] = blk; 515 } 516next: 517 /* 518 * Compute/validate number of cylinder groups. 519 */ 520 sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg; 521 if (sblock.fs_ncyl % sblock.fs_cpg) 522 sblock.fs_ncg++; 523 sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); 524 i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1); 525 if (cgdmin(&sblock, i) - cgbase(&sblock, i) >= sblock.fs_fpg) { 526 printf("inode blocks/cyl group (%ld) >= data blocks (%ld)\n", 527 cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag, 528 (long)(sblock.fs_fpg / sblock.fs_frag)); 529 printf("number of cylinders per cylinder group (%d) %s.\n", 530 sblock.fs_cpg, "must be increased"); 531 exit(29); 532 } 533 j = sblock.fs_ncg - 1; 534 if ((i = fssize - j * sblock.fs_fpg) < sblock.fs_fpg && 535 cgdmin(&sblock, j) - cgbase(&sblock, j) > i) { 536 if (j == 0) { 537 printf("Filesystem must have at least %d sectors\n", 538 NSPF(&sblock) * 539 (cgdmin(&sblock, 0) + 3 * sblock.fs_frag)); 540 exit(30); 541 } 542 printf( 543"Warning: inode blocks/cyl group (%ld) >= data blocks (%ld) in last\n", 544 (cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag, 545 i / sblock.fs_frag); 546 printf( 547" cylinder group. This implies %ld sector(s) cannot be allocated.\n", 548 i * NSPF(&sblock)); 549 sblock.fs_ncg--; 550 sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg; 551 sblock.fs_size = fssize = sblock.fs_ncyl * sblock.fs_spc / 552 NSPF(&sblock); 553 warn = 0; 554 } 555 if (warn) { 556 printf("Warning: %d sector(s) in last cylinder unallocated\n", 557 sblock.fs_spc - 558 (fssize * NSPF(&sblock) - (sblock.fs_ncyl - 1) * 559 sblock.fs_spc)); 560 } 561 /* 562 * fill in remaining fields of the super block 563 */ 564 sblock.fs_csaddr = cgdmin(&sblock, 0); 565 sblock.fs_cssize = 566 fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); 567 /* 568 * The superblock fields 'fs_csmask' and 'fs_csshift' are no 569 * longer used. However, we still initialise them so that the 570 * filesystem remains compatible with old kernels. 571 */ 572 i = sblock.fs_bsize / sizeof(struct csum); 573 sblock.fs_csmask = ~(i - 1); 574 for (sblock.fs_csshift = 0; i > 1; i >>= 1) 575 sblock.fs_csshift++; 576 fscs = (struct csum *)calloc(1, sblock.fs_cssize); 577 if (fscs == NULL) 578 errx(31, "calloc failed"); 579 sblock.fs_magic = FS_MAGIC; 580 sblock.fs_rotdelay = rotdelay; 581 sblock.fs_minfree = minfree; 582 sblock.fs_maxcontig = maxcontig; 583 sblock.fs_maxbpg = maxbpg; 584 sblock.fs_rps = rpm / 60; 585 sblock.fs_optim = opt; 586 sblock.fs_cgrotor = 0; 587 sblock.fs_cstotal.cs_ndir = 0; 588 sblock.fs_cstotal.cs_nbfree = 0; 589 sblock.fs_cstotal.cs_nifree = 0; 590 sblock.fs_cstotal.cs_nffree = 0; 591 sblock.fs_fmod = 0; 592 sblock.fs_ronly = 0; 593 sblock.fs_clean = 1; 594 sblock.fs_id[0] = (long)utime; 595 sblock.fs_id[1] = random(); 596 597 /* 598 * Dump out summary information about file system. 599 */ 600 printf("%s:\t%d sectors in %d %s of %d tracks, %d sectors\n", 601 fsys, sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl, 602 "cylinders", sblock.fs_ntrak, sblock.fs_nsect); 603#define B2MBFACTOR (1 / (1024.0 * 1024.0)) 604 printf("\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)%s\n", 605 (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, 606 sblock.fs_ncg, sblock.fs_cpg, 607 (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, 608 sblock.fs_ipg, 609 sblock.fs_flags & FS_DOSOFTDEP ? " SOFTUPDATES" : ""); 610#undef B2MBFACTOR 611 /* 612 * Now build the cylinders group blocks and 613 * then print out indices of cylinder groups. 614 */ 615 printf("super-block backups (for fsck -b #) at:\n"); 616 i = 0; 617 width = charsperline(); 618 for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { 619 initcg(cylno, utime); 620 j = snprintf(tmpbuf, sizeof(tmpbuf), " %ld%s", 621 fsbtodb(&sblock, cgsblock(&sblock, cylno)), 622 cylno < (sblock.fs_ncg-1) ? "," : ""); 623 if (j < 0) 624 tmpbuf[j = 0] = '\0'; 625 if (i + j >= width) { 626 printf("\n"); 627 i = 0; 628 } 629 i += j; 630 printf("%s", tmpbuf); 631 fflush(stdout); 632 } 633 printf("\n"); 634 if (Nflag) 635 exit(0); 636 /* 637 * Now construct the initial file system, 638 * then write out the super-block. 639 */ 640 fsinit(utime); 641 sblock.fs_time = utime; 642 wtfs((int)SBOFF / sectorsize, sbsize, (char *)&sblock); 643 for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) 644 wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), 645 sblock.fs_cssize - i < sblock.fs_bsize ? 646 sblock.fs_cssize - i : sblock.fs_bsize, 647 ((char *)fscs) + i); 648 /* 649 * Write out the duplicate super blocks 650 */ 651 for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 652 wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), 653 sbsize, (char *)&sblock); 654 wtfsflush(); 655 /* 656 * Update information about this partion in pack 657 * label, to that it may be updated on disk. 658 */ 659 pp->p_fstype = FS_BSDFFS; 660 pp->p_fsize = sblock.fs_fsize; 661 pp->p_frag = sblock.fs_frag; 662 pp->p_cpg = sblock.fs_cpg; 663} 664 665/* 666 * Initialize a cylinder group. 667 */ 668void 669initcg(cylno, utime) 670 int cylno; 671 time_t utime; 672{ 673 daddr_t cbase, d, dlower, dupper, dmax, blkno; 674 struct csum *cs; 675 long i, j; 676 677 /* 678 * Determine block bounds for cylinder group. 679 * Allow space for super block summary information in first 680 * cylinder group. 681 */ 682 cbase = cgbase(&sblock, cylno); 683 dmax = cbase + sblock.fs_fpg; 684 if (dmax > sblock.fs_size) 685 dmax = sblock.fs_size; 686 dlower = cgsblock(&sblock, cylno) - cbase; 687 dupper = cgdmin(&sblock, cylno) - cbase; 688 if (cylno == 0) 689 dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 690 cs = fscs + cylno; 691 memset(&acg, 0, sblock.fs_cgsize); 692 acg.cg_time = utime; 693 acg.cg_magic = CG_MAGIC; 694 acg.cg_cgx = cylno; 695 if (cylno == sblock.fs_ncg - 1) 696 acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg; 697 else 698 acg.cg_ncyl = sblock.fs_cpg; 699 acg.cg_niblk = sblock.fs_ipg; 700 acg.cg_ndblk = dmax - cbase; 701 if (sblock.fs_contigsumsize > 0) 702 acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; 703 acg.cg_btotoff = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield); 704 acg.cg_boff = acg.cg_btotoff + sblock.fs_cpg * sizeof(int32_t); 705 acg.cg_iusedoff = acg.cg_boff + 706 sblock.fs_cpg * sblock.fs_nrpos * sizeof(u_int16_t); 707 acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY); 708 if (sblock.fs_contigsumsize <= 0) { 709 acg.cg_nextfreeoff = acg.cg_freeoff + 710 howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), 711 NBBY); 712 } else { 713 acg.cg_clustersumoff = acg.cg_freeoff + howmany 714 (sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY) - 715 sizeof(u_int32_t); 716 acg.cg_clustersumoff = 717 roundup(acg.cg_clustersumoff, sizeof(u_int32_t)); 718 acg.cg_clusteroff = acg.cg_clustersumoff + 719 (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); 720 acg.cg_nextfreeoff = acg.cg_clusteroff + howmany 721 (sblock.fs_cpg * sblock.fs_spc / NSPB(&sblock), NBBY); 722 } 723 if (acg.cg_nextfreeoff - (long)(&acg.cg_firstfield) > 724 sblock.fs_cgsize) { 725 printf("Panic: cylinder group too big\n"); 726 exit(37); 727 } 728 acg.cg_cs.cs_nifree += sblock.fs_ipg; 729 if (cylno == 0) 730 for (i = 0; i < ROOTINO; i++) { 731 setbit(cg_inosused(&acg), i); 732 acg.cg_cs.cs_nifree--; 733 } 734 for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag) { 735 for (j = 0; j < sblock.fs_bsize / sizeof(struct dinode); j++) 736 zino[j].di_gen = random(); 737 wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), 738 sblock.fs_bsize, (char *)zino); 739 } 740 if (cylno > 0) { 741 /* 742 * In cylno 0, beginning space is reserved 743 * for boot and super blocks. 744 */ 745 for (d = 0; d < dlower; d += sblock.fs_frag) { 746 blkno = d / sblock.fs_frag; 747 setblock(&sblock, cg_blksfree(&acg), blkno); 748 if (sblock.fs_contigsumsize > 0) 749 setbit(cg_clustersfree(&acg), blkno); 750 acg.cg_cs.cs_nbfree++; 751 cg_blktot(&acg)[cbtocylno(&sblock, d)]++; 752 cg_blks(&sblock, &acg, cbtocylno(&sblock, d)) 753 [cbtorpos(&sblock, d)]++; 754 } 755 sblock.fs_dsize += dlower; 756 } 757 sblock.fs_dsize += acg.cg_ndblk - dupper; 758 if ((i = dupper % sblock.fs_frag)) { 759 acg.cg_frsum[sblock.fs_frag - i]++; 760 for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { 761 setbit(cg_blksfree(&acg), dupper); 762 acg.cg_cs.cs_nffree++; 763 } 764 } 765 for (d = dupper; d + sblock.fs_frag <= dmax - cbase;) { 766 blkno = d / sblock.fs_frag; 767 setblock(&sblock, cg_blksfree(&acg), blkno); 768 if (sblock.fs_contigsumsize > 0) 769 setbit(cg_clustersfree(&acg), blkno); 770 acg.cg_cs.cs_nbfree++; 771 cg_blktot(&acg)[cbtocylno(&sblock, d)]++; 772 cg_blks(&sblock, &acg, cbtocylno(&sblock, d)) 773 [cbtorpos(&sblock, d)]++; 774 d += sblock.fs_frag; 775 } 776 if (d < dmax - cbase) { 777 acg.cg_frsum[dmax - cbase - d]++; 778 for (; d < dmax - cbase; d++) { 779 setbit(cg_blksfree(&acg), d); 780 acg.cg_cs.cs_nffree++; 781 } 782 } 783 if (sblock.fs_contigsumsize > 0) { 784 int32_t *sump = cg_clustersum(&acg); 785 u_char *mapp = cg_clustersfree(&acg); 786 int map = *mapp++; 787 int bit = 1; 788 int run = 0; 789 790 for (i = 0; i < acg.cg_nclusterblks; i++) { 791 if ((map & bit) != 0) 792 run++; 793 else if (run != 0) { 794 if (run > sblock.fs_contigsumsize) 795 run = sblock.fs_contigsumsize; 796 sump[run]++; 797 run = 0; 798 } 799 if ((i & (NBBY - 1)) != NBBY - 1) 800 bit <<= 1; 801 else { 802 map = *mapp++; 803 bit = 1; 804 } 805 } 806 if (run != 0) { 807 if (run > sblock.fs_contigsumsize) 808 run = sblock.fs_contigsumsize; 809 sump[run]++; 810 } 811 } 812 sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir; 813 sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree; 814 sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree; 815 sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree; 816 *cs = acg.cg_cs; 817 wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), 818 sblock.fs_bsize, (char *)&acg); 819} 820 821/* 822 * initialize the file system 823 */ 824struct dinode node; 825 826#ifdef LOSTDIR 827#define PREDEFDIR 3 828#else 829#define PREDEFDIR 2 830#endif 831 832struct direct root_dir[] = { 833 { ROOTINO, sizeof(struct direct), DT_DIR, 1, "." }, 834 { ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." }, 835#ifdef LOSTDIR 836 { LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 10, "lost+found" }, 837#endif 838}; 839struct odirect { 840 u_long d_ino; 841 u_short d_reclen; 842 u_short d_namlen; 843 u_char d_name[MAXNAMLEN + 1]; 844} oroot_dir[] = { 845 { ROOTINO, sizeof(struct direct), 1, "." }, 846 { ROOTINO, sizeof(struct direct), 2, ".." }, 847#ifdef LOSTDIR 848 { LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found" }, 849#endif 850}; 851#ifdef LOSTDIR 852struct direct lost_found_dir[] = { 853 { LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 1, "." }, 854 { ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." }, 855 { 0, DIRBLKSIZ, 0, 0, 0 }, 856}; 857struct odirect olost_found_dir[] = { 858 { LOSTFOUNDINO, sizeof(struct direct), 1, "." }, 859 { ROOTINO, sizeof(struct direct), 2, ".." }, 860 { 0, DIRBLKSIZ, 0, 0 }, 861}; 862#endif 863char buf[MAXBSIZE]; 864 865void 866fsinit(utime) 867 time_t utime; 868{ 869#ifdef LOSTDIR 870 int i; 871#endif 872 873 /* 874 * initialize the node 875 */ 876 node.di_atime = utime; 877 node.di_mtime = utime; 878 node.di_ctime = utime; 879#ifdef LOSTDIR 880 /* 881 * create the lost+found directory 882 */ 883 if (Oflag) { 884 (void)makedir((struct direct *)olost_found_dir, 2); 885 for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ) 886 memmove(&buf[i], &olost_found_dir[2], 887 DIRSIZ(0, &olost_found_dir[2])); 888 } else { 889 (void)makedir(lost_found_dir, 2); 890 for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ) 891 memmove(&buf[i], &lost_found_dir[2], 892 DIRSIZ(0, &lost_found_dir[2])); 893 } 894 node.di_mode = IFDIR | UMASK; 895 node.di_nlink = 2; 896 node.di_size = sblock.fs_bsize; 897 node.di_db[0] = alloc(node.di_size, node.di_mode); 898 node.di_blocks = btodb(fragroundup(&sblock, node.di_size)); 899 wtfs(fsbtodb(&sblock, node.di_db[0]), node.di_size, buf); 900 iput(&node, LOSTFOUNDINO); 901#endif 902 /* 903 * create the root directory 904 */ 905 node.di_mode = IFDIR | UMASK; 906 node.di_nlink = PREDEFDIR; 907 if (Oflag) 908 node.di_size = makedir((struct direct *)oroot_dir, PREDEFDIR); 909 else 910 node.di_size = makedir(root_dir, PREDEFDIR); 911 node.di_db[0] = alloc(sblock.fs_fsize, node.di_mode); 912 node.di_blocks = btodb(fragroundup(&sblock, node.di_size)); 913 wtfs(fsbtodb(&sblock, node.di_db[0]), sblock.fs_fsize, buf); 914 iput(&node, ROOTINO); 915} 916 917/* 918 * construct a set of directory entries in "buf". 919 * return size of directory. 920 */ 921int 922makedir(protodir, entries) 923 struct direct *protodir; 924 int entries; 925{ 926 char *cp; 927 int i, spcleft; 928 929 spcleft = DIRBLKSIZ; 930 for (cp = buf, i = 0; i < entries - 1; i++) { 931 protodir[i].d_reclen = DIRSIZ(0, &protodir[i]); 932 memmove(cp, &protodir[i], protodir[i].d_reclen); 933 cp += protodir[i].d_reclen; 934 spcleft -= protodir[i].d_reclen; 935 } 936 protodir[i].d_reclen = spcleft; 937 memmove(cp, &protodir[i], DIRSIZ(0, &protodir[i])); 938 return (DIRBLKSIZ); 939} 940 941/* 942 * allocate a block or frag 943 */ 944daddr_t 945alloc(size, mode) 946 int size; 947 int mode; 948{ 949 int i, frag; 950 daddr_t d, blkno; 951 952 rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, 953 (char *)&acg); 954 if (acg.cg_magic != CG_MAGIC) { 955 printf("cg 0: bad magic number\n"); 956 return (0); 957 } 958 if (acg.cg_cs.cs_nbfree == 0) { 959 printf("first cylinder group ran out of space\n"); 960 return (0); 961 } 962 for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag) 963 if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag)) 964 goto goth; 965 printf("internal error: can't find block in cyl 0\n"); 966 return (0); 967goth: 968 blkno = fragstoblks(&sblock, d); 969 clrblock(&sblock, cg_blksfree(&acg), blkno); 970 if (sblock.fs_contigsumsize > 0) 971 clrbit(cg_clustersfree(&acg), blkno); 972 acg.cg_cs.cs_nbfree--; 973 sblock.fs_cstotal.cs_nbfree--; 974 fscs[0].cs_nbfree--; 975 if (mode & IFDIR) { 976 acg.cg_cs.cs_ndir++; 977 sblock.fs_cstotal.cs_ndir++; 978 fscs[0].cs_ndir++; 979 } 980 cg_blktot(&acg)[cbtocylno(&sblock, d)]--; 981 cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--; 982 if (size != sblock.fs_bsize) { 983 frag = howmany(size, sblock.fs_fsize); 984 fscs[0].cs_nffree += sblock.fs_frag - frag; 985 sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag; 986 acg.cg_cs.cs_nffree += sblock.fs_frag - frag; 987 acg.cg_frsum[sblock.fs_frag - frag]++; 988 for (i = frag; i < sblock.fs_frag; i++) 989 setbit(cg_blksfree(&acg), d + i); 990 } 991 wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, 992 (char *)&acg); 993 return (d); 994} 995 996/* 997 * Calculate number of inodes per group. 998 */ 999long 1000calcipg(cpg, bpcg, usedbp) 1001 long cpg; 1002 long bpcg; 1003 off_t *usedbp; 1004{ 1005 int i; 1006 long ipg, new_ipg, ncg, ncyl; 1007 off_t usedb; 1008 1009 /* 1010 * Prepare to scale by fssize / (number of sectors in cylinder groups). 1011 * Note that fssize is still in sectors, not filesystem blocks. 1012 */ 1013 ncyl = howmany(fssize, (u_int)secpercyl); 1014 ncg = howmany(ncyl, cpg); 1015 /* 1016 * Iterate a few times to allow for ipg depending on itself. 1017 */ 1018 ipg = 0; 1019 for (i = 0; i < 10; i++) { 1020 usedb = (sblock.fs_iblkno + ipg / INOPF(&sblock)) * 1021 NSPF(&sblock) * (off_t)sectorsize; 1022 new_ipg = (cpg * (quad_t)bpcg - usedb) / density * 1023 fssize / ncg / secpercyl / cpg; 1024 new_ipg = roundup(new_ipg, INOPB(&sblock)); 1025 if (new_ipg == ipg) 1026 break; 1027 ipg = new_ipg; 1028 } 1029 *usedbp = usedb; 1030 return (ipg); 1031} 1032 1033/* 1034 * Allocate an inode on the disk 1035 */ 1036void 1037iput(ip, ino) 1038 struct dinode *ip; 1039 ino_t ino; 1040{ 1041 struct dinode buf[MAXINOPB]; 1042 daddr_t d; 1043 int c; 1044 1045 ip->di_gen = random(); 1046 c = ino_to_cg(&sblock, ino); 1047 rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, 1048 (char *)&acg); 1049 if (acg.cg_magic != CG_MAGIC) { 1050 printf("cg 0: bad magic number\n"); 1051 exit(31); 1052 } 1053 acg.cg_cs.cs_nifree--; 1054 setbit(cg_inosused(&acg), ino); 1055 wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, 1056 (char *)&acg); 1057 sblock.fs_cstotal.cs_nifree--; 1058 fscs[0].cs_nifree--; 1059 if (ino >= sblock.fs_ipg * sblock.fs_ncg) { 1060 printf("fsinit: inode value out of range (%d).\n", ino); 1061 exit(32); 1062 } 1063 d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino)); 1064 rdfs(d, sblock.fs_bsize, (char *)buf); 1065 buf[ino_to_fsbo(&sblock, ino)] = *ip; 1066 wtfs(d, sblock.fs_bsize, (char *)buf); 1067} 1068 1069/* 1070 * read a block from the file system 1071 */ 1072void 1073rdfs(bno, size, bf) 1074 daddr_t bno; 1075 int size; 1076 char *bf; 1077{ 1078 int n; 1079 1080 wtfsflush(); 1081 if (lseek(fsi, (off_t)bno * sectorsize, 0) < 0) { 1082 printf("seek error: %ld\n", (long)bno); 1083 err(33, "rdfs"); 1084 } 1085 n = read(fsi, bf, size); 1086 if (n != size) { 1087 printf("read error: %ld\n", (long)bno); 1088 err(34, "rdfs"); 1089 } 1090} 1091 1092#define WCSIZE (128 * 1024) 1093daddr_t wc_sect; /* units of sectorsize */ 1094int wc_end; /* bytes */ 1095static char wc[WCSIZE]; /* bytes */ 1096 1097/* 1098 * Flush dirty write behind buffer. 1099 */ 1100void 1101wtfsflush() 1102{ 1103 int n; 1104 if (wc_end) { 1105 if (lseek(fso, (off_t)wc_sect * sectorsize, SEEK_SET) < 0) { 1106 printf("seek error: %ld\n", (long)wc_sect); 1107 err(35, "wtfs - writecombine"); 1108 } 1109 n = write(fso, wc, wc_end); 1110 if (n != wc_end) { 1111 printf("write error: %ld\n", (long)wc_sect); 1112 err(36, "wtfs - writecombine"); 1113 } 1114 wc_end = 0; 1115 } 1116} 1117 1118/* 1119 * write a block to the file system 1120 */ 1121void 1122wtfs(bno, size, bf) 1123 daddr_t bno; 1124 int size; 1125 char *bf; 1126{ 1127 int n; 1128 int done; 1129 1130 if (Nflag) 1131 return; 1132 done = 0; 1133 if (wc_end == 0 && size <= WCSIZE) { 1134 wc_sect = bno; 1135 bcopy(bf, wc, size); 1136 wc_end = size; 1137 if (wc_end < WCSIZE) 1138 return; 1139 done = 1; 1140 } 1141 if ((off_t)wc_sect * sectorsize + wc_end == (off_t)bno * sectorsize && 1142 wc_end + size <= WCSIZE) { 1143 bcopy(bf, wc + wc_end, size); 1144 wc_end += size; 1145 if (wc_end < WCSIZE) 1146 return; 1147 done = 1; 1148 } 1149 wtfsflush(); 1150 if (done) 1151 return; 1152 if (lseek(fso, (off_t)bno * sectorsize, SEEK_SET) < 0) { 1153 printf("seek error: %ld\n", (long)bno); 1154 err(35, "wtfs"); 1155 } 1156 n = write(fso, bf, size); 1157 if (n != size) { 1158 printf("write error: %ld\n", (long)bno); 1159 err(36, "wtfs"); 1160 } 1161} 1162 1163/* 1164 * check if a block is available 1165 */ 1166int 1167isblock(fs, cp, h) 1168 struct fs *fs; 1169 unsigned char *cp; 1170 int h; 1171{ 1172 unsigned char mask; 1173 1174 switch (fs->fs_frag) { 1175 case 8: 1176 return (cp[h] == 0xff); 1177 case 4: 1178 mask = 0x0f << ((h & 0x1) << 2); 1179 return ((cp[h >> 1] & mask) == mask); 1180 case 2: 1181 mask = 0x03 << ((h & 0x3) << 1); 1182 return ((cp[h >> 2] & mask) == mask); 1183 case 1: 1184 mask = 0x01 << (h & 0x7); 1185 return ((cp[h >> 3] & mask) == mask); 1186 default: 1187 fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag); 1188 return (0); 1189 } 1190} 1191 1192/* 1193 * take a block out of the map 1194 */ 1195void 1196clrblock(fs, cp, h) 1197 struct fs *fs; 1198 unsigned char *cp; 1199 int h; 1200{ 1201 switch ((fs)->fs_frag) { 1202 case 8: 1203 cp[h] = 0; 1204 return; 1205 case 4: 1206 cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 1207 return; 1208 case 2: 1209 cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 1210 return; 1211 case 1: 1212 cp[h >> 3] &= ~(0x01 << (h & 0x7)); 1213 return; 1214 default: 1215 fprintf(stderr, "clrblock bad fs_frag %d\n", fs->fs_frag); 1216 return; 1217 } 1218} 1219 1220/* 1221 * put a block into the map 1222 */ 1223void 1224setblock(fs, cp, h) 1225 struct fs *fs; 1226 unsigned char *cp; 1227 int h; 1228{ 1229 switch (fs->fs_frag) { 1230 case 8: 1231 cp[h] = 0xff; 1232 return; 1233 case 4: 1234 cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 1235 return; 1236 case 2: 1237 cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 1238 return; 1239 case 1: 1240 cp[h >> 3] |= (0x01 << (h & 0x7)); 1241 return; 1242 default: 1243 fprintf(stderr, "setblock bad fs_frag %d\n", fs->fs_frag); 1244 return; 1245 } 1246} 1247 1248/* 1249 * Determine the number of characters in a 1250 * single line. 1251 */ 1252 1253static int 1254charsperline() 1255{ 1256 int columns; 1257 char *cp; 1258 struct winsize ws; 1259 1260 columns = 0; 1261 if (ioctl(0, TIOCGWINSZ, &ws) != -1) 1262 columns = ws.ws_col; 1263 if (columns == 0 && (cp = getenv("COLUMNS"))) 1264 columns = atoi(cp); 1265 if (columns == 0) 1266 columns = 80; /* last resort */ 1267 return (columns); 1268} 1269