mkfs.c revision 13769
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1980, 1989, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 351558Srgrimesstatic char sccsid[] = "@(#)mkfs.c 8.3 (Berkeley) 2/3/94"; 361558Srgrimes#endif /* not lint */ 371558Srgrimes 381558Srgrimes#include <unistd.h> 391558Srgrimes#include <sys/param.h> 401558Srgrimes#include <sys/time.h> 411558Srgrimes#include <sys/wait.h> 421558Srgrimes#include <sys/resource.h> 431558Srgrimes#include <ufs/ufs/dinode.h> 441558Srgrimes#include <ufs/ufs/dir.h> 451558Srgrimes#include <ufs/ffs/fs.h> 461558Srgrimes#include <sys/disklabel.h> 473550Sphk#include <sys/file.h> 483550Sphk#include <sys/mman.h> 4913637Sjoerg#include <sys/ioctl.h> 501558Srgrimes 511558Srgrimes#ifndef STANDALONE 521558Srgrimes#include <a.out.h> 531558Srgrimes#include <stdio.h> 541558Srgrimes#endif 551558Srgrimes 561558Srgrimes/* 571558Srgrimes * make file system for cylinder-group style file systems 581558Srgrimes */ 591558Srgrimes 601558Srgrimes/* 611558Srgrimes * We limit the size of the inode map to be no more than a 621558Srgrimes * third of the cylinder group space, since we must leave at 631558Srgrimes * least an equal amount of space for the block map. 641558Srgrimes * 651558Srgrimes * N.B.: MAXIPG must be a multiple of INOPB(fs). 661558Srgrimes */ 671558Srgrimes#define MAXIPG(fs) roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs)) 681558Srgrimes 691558Srgrimes#define UMASK 0755 701558Srgrimes#define MAXINOPB (MAXBSIZE / sizeof(struct dinode)) 711558Srgrimes#define POWEROF2(num) (((num) & ((num) - 1)) == 0) 721558Srgrimes 731558Srgrimes/* 741558Srgrimes * variables set up by front end. 751558Srgrimes */ 761558Srgrimesextern int mfs; /* run as the memory based filesystem */ 771558Srgrimesextern int Nflag; /* run mkfs without writing file system */ 781558Srgrimesextern int Oflag; /* format as an 4.3BSD file system */ 791558Srgrimesextern int fssize; /* file system size */ 801558Srgrimesextern int ntracks; /* # tracks/cylinder */ 811558Srgrimesextern int nsectors; /* # sectors/track */ 821558Srgrimesextern int nphyssectors; /* # sectors/track including spares */ 831558Srgrimesextern int secpercyl; /* sectors per cylinder */ 841558Srgrimesextern int sectorsize; /* bytes/sector */ 851558Srgrimesextern int rpm; /* revolutions/minute of drive */ 861558Srgrimesextern int interleave; /* hardware sector interleave */ 871558Srgrimesextern int trackskew; /* sector 0 skew, per track */ 881558Srgrimesextern int headswitch; /* head switch time, usec */ 891558Srgrimesextern int trackseek; /* track-to-track seek, usec */ 901558Srgrimesextern int fsize; /* fragment size */ 911558Srgrimesextern int bsize; /* block size */ 921558Srgrimesextern int cpg; /* cylinders/cylinder group */ 931558Srgrimesextern int cpgflg; /* cylinders/cylinder group flag was given */ 941558Srgrimesextern int minfree; /* free space threshold */ 951558Srgrimesextern int opt; /* optimization preference (space or time) */ 961558Srgrimesextern int density; /* number of bytes per inode */ 971558Srgrimesextern int maxcontig; /* max contiguous blocks to allocate */ 981558Srgrimesextern int rotdelay; /* rotational delay between blocks */ 991558Srgrimesextern int maxbpg; /* maximum blocks per file in a cyl group */ 1001558Srgrimesextern int nrpos; /* # of distinguished rotational positions */ 1011558Srgrimesextern int bbsize; /* boot block size */ 1021558Srgrimesextern int sbsize; /* superblock size */ 1031558Srgrimesextern u_long memleft; /* virtual memory available */ 1041558Srgrimesextern caddr_t membase; /* start address of memory based filesystem */ 1051558Srgrimesextern caddr_t malloc(), calloc(); 1063550Sphkextern char * filename; 1071558Srgrimes 1081558Srgrimesunion { 1091558Srgrimes struct fs fs; 1101558Srgrimes char pad[SBSIZE]; 1111558Srgrimes} fsun; 1121558Srgrimes#define sblock fsun.fs 1131558Srgrimesstruct csum *fscs; 1141558Srgrimes 1151558Srgrimesunion { 1161558Srgrimes struct cg cg; 1171558Srgrimes char pad[MAXBSIZE]; 1181558Srgrimes} cgun; 1191558Srgrimes#define acg cgun.cg 1201558Srgrimes 1211558Srgrimesstruct dinode zino[MAXBSIZE / sizeof(struct dinode)]; 1221558Srgrimes 1231558Srgrimesint fsi, fso; 1241558Srgrimesdaddr_t alloc(); 12513769Sjoergstatic int charsperline(); 1261558Srgrimes 1271558Srgrimesmkfs(pp, fsys, fi, fo) 1281558Srgrimes struct partition *pp; 1291558Srgrimes char *fsys; 1301558Srgrimes int fi, fo; 1311558Srgrimes{ 1321558Srgrimes register long i, mincpc, mincpg, inospercg; 1331558Srgrimes long cylno, rpos, blk, j, warn = 0; 1341558Srgrimes long used, mincpgcnt, bpcg; 1351558Srgrimes long mapcramped, inodecramped; 1361558Srgrimes long postblsize, rotblsize, totalsbsize; 1373550Sphk int ppid, status, fd; 1381558Srgrimes time_t utime; 1391558Srgrimes quad_t sizepb; 1401558Srgrimes void started(); 14113769Sjoerg int width; 14213769Sjoerg char tmpbuf[100]; /* XXX this will break in about 2,500 years */ 1431558Srgrimes 1441558Srgrimes#ifndef STANDALONE 1451558Srgrimes time(&utime); 1461558Srgrimes#endif 1471558Srgrimes if (mfs) { 1481558Srgrimes ppid = getpid(); 1491558Srgrimes (void) signal(SIGUSR1, started); 1501558Srgrimes if (i = fork()) { 1511558Srgrimes if (i == -1) { 1521558Srgrimes perror("mfs"); 1531558Srgrimes exit(10); 1541558Srgrimes } 1551558Srgrimes if (waitpid(i, &status, 0) != -1 && WIFEXITED(status)) 1561558Srgrimes exit(WEXITSTATUS(status)); 1571558Srgrimes exit(11); 1581558Srgrimes /* NOTREACHED */ 1591558Srgrimes } 1601558Srgrimes (void)malloc(0); 1613550Sphk if(filename) { 1623550Sphk unsigned char buf[BUFSIZ]; 1633550Sphk unsigned long l,l1; 1643550Sphk fd = open(filename,O_RDWR|O_TRUNC|O_CREAT,0644); 1653550Sphk if(fd < 0) { 1663550Sphk perror(filename); 1673550Sphk exit(12); 1683550Sphk } 1693550Sphk for(l=0;l< fssize * sectorsize;l += l1) { 1703550Sphk l1 = fssize * sectorsize; 1713550Sphk if (BUFSIZ < l1) 1723550Sphk l1 = BUFSIZ; 1733550Sphk if (l1 != write(fd,buf,l1)) { 1743550Sphk perror(filename); 1753550Sphk exit(12); 1763550Sphk } 1773550Sphk } 1783550Sphk membase = mmap( 1793550Sphk 0, 1803550Sphk fssize * sectorsize, 1813550Sphk PROT_READ|PROT_WRITE, 1823550Sphk MAP_SHARED, 1833550Sphk fd, 1843550Sphk 0); 1853550Sphk if((int)membase == -1) { 1863550Sphk perror("mmap"); 1873550Sphk exit(12); 1883550Sphk } 1893550Sphk close(fd); 1903550Sphk } else { 1913550Sphk if (fssize * sectorsize > memleft) 1923550Sphk fssize = (memleft - 16384) / sectorsize; 1933550Sphk if ((membase = malloc(fssize * sectorsize)) == 0) 1943550Sphk exit(12); 1953550Sphk } 1961558Srgrimes } 1971558Srgrimes fsi = fi; 1981558Srgrimes fso = fo; 1991558Srgrimes if (Oflag) { 2001558Srgrimes sblock.fs_inodefmt = FS_42INODEFMT; 2011558Srgrimes sblock.fs_maxsymlinklen = 0; 2021558Srgrimes } else { 2031558Srgrimes sblock.fs_inodefmt = FS_44INODEFMT; 2041558Srgrimes sblock.fs_maxsymlinklen = MAXSYMLINKLEN; 2051558Srgrimes } 2061558Srgrimes /* 2071558Srgrimes * Validate the given file system size. 2081558Srgrimes * Verify that its last block can actually be accessed. 2091558Srgrimes */ 2101558Srgrimes if (fssize <= 0) 2111558Srgrimes printf("preposterous size %d\n", fssize), exit(13); 2121558Srgrimes wtfs(fssize - 1, sectorsize, (char *)&sblock); 2131558Srgrimes /* 2141558Srgrimes * collect and verify the sector and track info 2151558Srgrimes */ 2161558Srgrimes sblock.fs_nsect = nsectors; 2171558Srgrimes sblock.fs_ntrak = ntracks; 2181558Srgrimes if (sblock.fs_ntrak <= 0) 2191558Srgrimes printf("preposterous ntrak %d\n", sblock.fs_ntrak), exit(14); 2201558Srgrimes if (sblock.fs_nsect <= 0) 2211558Srgrimes printf("preposterous nsect %d\n", sblock.fs_nsect), exit(15); 2221558Srgrimes /* 2231558Srgrimes * collect and verify the block and fragment sizes 2241558Srgrimes */ 2251558Srgrimes sblock.fs_bsize = bsize; 2261558Srgrimes sblock.fs_fsize = fsize; 2271558Srgrimes if (!POWEROF2(sblock.fs_bsize)) { 2281558Srgrimes printf("block size must be a power of 2, not %d\n", 2291558Srgrimes sblock.fs_bsize); 2301558Srgrimes exit(16); 2311558Srgrimes } 2321558Srgrimes if (!POWEROF2(sblock.fs_fsize)) { 2331558Srgrimes printf("fragment size must be a power of 2, not %d\n", 2341558Srgrimes sblock.fs_fsize); 2351558Srgrimes exit(17); 2361558Srgrimes } 2371558Srgrimes if (sblock.fs_fsize < sectorsize) { 2381558Srgrimes printf("fragment size %d is too small, minimum is %d\n", 2391558Srgrimes sblock.fs_fsize, sectorsize); 2401558Srgrimes exit(18); 2411558Srgrimes } 2421558Srgrimes if (sblock.fs_bsize < MINBSIZE) { 2431558Srgrimes printf("block size %d is too small, minimum is %d\n", 2441558Srgrimes sblock.fs_bsize, MINBSIZE); 2451558Srgrimes exit(19); 2461558Srgrimes } 2471558Srgrimes if (sblock.fs_bsize < sblock.fs_fsize) { 2481558Srgrimes printf("block size (%d) cannot be smaller than fragment size (%d)\n", 2491558Srgrimes sblock.fs_bsize, sblock.fs_fsize); 2501558Srgrimes exit(20); 2511558Srgrimes } 2521558Srgrimes sblock.fs_bmask = ~(sblock.fs_bsize - 1); 2531558Srgrimes sblock.fs_fmask = ~(sblock.fs_fsize - 1); 2541558Srgrimes sblock.fs_qbmask = ~sblock.fs_bmask; 2551558Srgrimes sblock.fs_qfmask = ~sblock.fs_fmask; 2561558Srgrimes for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1) 2571558Srgrimes sblock.fs_bshift++; 2581558Srgrimes for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1) 2591558Srgrimes sblock.fs_fshift++; 2601558Srgrimes sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); 2611558Srgrimes for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1) 2621558Srgrimes sblock.fs_fragshift++; 2631558Srgrimes if (sblock.fs_frag > MAXFRAG) { 2641558Srgrimes printf("fragment size %d is too small, minimum with block size %d is %d\n", 2651558Srgrimes sblock.fs_fsize, sblock.fs_bsize, 2661558Srgrimes sblock.fs_bsize / MAXFRAG); 2671558Srgrimes exit(21); 2681558Srgrimes } 2691558Srgrimes sblock.fs_nrpos = nrpos; 2701558Srgrimes sblock.fs_nindir = sblock.fs_bsize / sizeof(daddr_t); 2711558Srgrimes sblock.fs_inopb = sblock.fs_bsize / sizeof(struct dinode); 2721558Srgrimes sblock.fs_nspf = sblock.fs_fsize / sectorsize; 2731558Srgrimes for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1) 2741558Srgrimes sblock.fs_fsbtodb++; 2751558Srgrimes sblock.fs_sblkno = 2761558Srgrimes roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag); 2771558Srgrimes sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno + 2781558Srgrimes roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag)); 2791558Srgrimes sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; 2801558Srgrimes sblock.fs_cgoffset = roundup( 2811558Srgrimes howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag); 2821558Srgrimes for (sblock.fs_cgmask = 0xffffffff, i = sblock.fs_ntrak; i > 1; i >>= 1) 2831558Srgrimes sblock.fs_cgmask <<= 1; 2841558Srgrimes if (!POWEROF2(sblock.fs_ntrak)) 2851558Srgrimes sblock.fs_cgmask <<= 1; 2861558Srgrimes sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; 2871558Srgrimes for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) { 2881558Srgrimes sizepb *= NINDIR(&sblock); 2891558Srgrimes sblock.fs_maxfilesize += sizepb; 2901558Srgrimes } 2913767Sdg /* XXX - hack to prevent overflow of a 32bit block number */ 2923767Sdg sblock.fs_maxfilesize = MIN(sblock.fs_maxfilesize, (u_quad_t) 1 << 39); 2931558Srgrimes /* 2941558Srgrimes * Validate specified/determined secpercyl 2951558Srgrimes * and calculate minimum cylinders per group. 2961558Srgrimes */ 2971558Srgrimes sblock.fs_spc = secpercyl; 2981558Srgrimes for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc; 2991558Srgrimes sblock.fs_cpc > 1 && (i & 1) == 0; 3001558Srgrimes sblock.fs_cpc >>= 1, i >>= 1) 3011558Srgrimes /* void */; 3021558Srgrimes mincpc = sblock.fs_cpc; 3031558Srgrimes bpcg = sblock.fs_spc * sectorsize; 3041558Srgrimes inospercg = roundup(bpcg / sizeof(struct dinode), INOPB(&sblock)); 3051558Srgrimes if (inospercg > MAXIPG(&sblock)) 3061558Srgrimes inospercg = MAXIPG(&sblock); 3071558Srgrimes used = (sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock); 3081558Srgrimes mincpgcnt = howmany(sblock.fs_cgoffset * (~sblock.fs_cgmask) + used, 3091558Srgrimes sblock.fs_spc); 3101558Srgrimes mincpg = roundup(mincpgcnt, mincpc); 3111558Srgrimes /* 3121558Srgrimes * Ensure that cylinder group with mincpg has enough space 3131558Srgrimes * for block maps. 3141558Srgrimes */ 3151558Srgrimes sblock.fs_cpg = mincpg; 3161558Srgrimes sblock.fs_ipg = inospercg; 3171558Srgrimes if (maxcontig > 1) 3181558Srgrimes sblock.fs_contigsumsize = MIN(maxcontig, FS_MAXCONTIG); 3191558Srgrimes mapcramped = 0; 3201558Srgrimes while (CGSIZE(&sblock) > sblock.fs_bsize) { 3211558Srgrimes mapcramped = 1; 3221558Srgrimes if (sblock.fs_bsize < MAXBSIZE) { 3231558Srgrimes sblock.fs_bsize <<= 1; 3241558Srgrimes if ((i & 1) == 0) { 3251558Srgrimes i >>= 1; 3261558Srgrimes } else { 3271558Srgrimes sblock.fs_cpc <<= 1; 3281558Srgrimes mincpc <<= 1; 3291558Srgrimes mincpg = roundup(mincpgcnt, mincpc); 3301558Srgrimes sblock.fs_cpg = mincpg; 3311558Srgrimes } 3321558Srgrimes sblock.fs_frag <<= 1; 3331558Srgrimes sblock.fs_fragshift += 1; 3341558Srgrimes if (sblock.fs_frag <= MAXFRAG) 3351558Srgrimes continue; 3361558Srgrimes } 3371558Srgrimes if (sblock.fs_fsize == sblock.fs_bsize) { 3381558Srgrimes printf("There is no block size that"); 3391558Srgrimes printf(" can support this disk\n"); 3401558Srgrimes exit(22); 3411558Srgrimes } 3421558Srgrimes sblock.fs_frag >>= 1; 3431558Srgrimes sblock.fs_fragshift -= 1; 3441558Srgrimes sblock.fs_fsize <<= 1; 3451558Srgrimes sblock.fs_nspf <<= 1; 3461558Srgrimes } 3471558Srgrimes /* 3481558Srgrimes * Ensure that cylinder group with mincpg has enough space for inodes. 3491558Srgrimes */ 3501558Srgrimes inodecramped = 0; 3511558Srgrimes used *= sectorsize; 3521558Srgrimes inospercg = roundup((mincpg * bpcg - used) / density, INOPB(&sblock)); 3531558Srgrimes sblock.fs_ipg = inospercg; 3541558Srgrimes while (inospercg > MAXIPG(&sblock)) { 3551558Srgrimes inodecramped = 1; 3561558Srgrimes if (mincpc == 1 || sblock.fs_frag == 1 || 3571558Srgrimes sblock.fs_bsize == MINBSIZE) 3581558Srgrimes break; 3591558Srgrimes printf("With a block size of %d %s %d\n", sblock.fs_bsize, 3601558Srgrimes "minimum bytes per inode is", 3611558Srgrimes (mincpg * bpcg - used) / MAXIPG(&sblock) + 1); 3621558Srgrimes sblock.fs_bsize >>= 1; 3631558Srgrimes sblock.fs_frag >>= 1; 3641558Srgrimes sblock.fs_fragshift -= 1; 3651558Srgrimes mincpc >>= 1; 3661558Srgrimes sblock.fs_cpg = roundup(mincpgcnt, mincpc); 3671558Srgrimes if (CGSIZE(&sblock) > sblock.fs_bsize) { 3681558Srgrimes sblock.fs_bsize <<= 1; 3691558Srgrimes break; 3701558Srgrimes } 3711558Srgrimes mincpg = sblock.fs_cpg; 3721558Srgrimes inospercg = 3731558Srgrimes roundup((mincpg * bpcg - used) / density, INOPB(&sblock)); 3741558Srgrimes sblock.fs_ipg = inospercg; 3751558Srgrimes } 3761558Srgrimes if (inodecramped) { 3771558Srgrimes if (inospercg > MAXIPG(&sblock)) { 3781558Srgrimes printf("Minimum bytes per inode is %d\n", 3791558Srgrimes (mincpg * bpcg - used) / MAXIPG(&sblock) + 1); 3801558Srgrimes } else if (!mapcramped) { 3811558Srgrimes printf("With %d bytes per inode, ", density); 3821558Srgrimes printf("minimum cylinders per group is %d\n", mincpg); 3831558Srgrimes } 3841558Srgrimes } 3851558Srgrimes if (mapcramped) { 3861558Srgrimes printf("With %d sectors per cylinder, ", sblock.fs_spc); 3871558Srgrimes printf("minimum cylinders per group is %d\n", mincpg); 3881558Srgrimes } 3891558Srgrimes if (inodecramped || mapcramped) { 3901558Srgrimes if (sblock.fs_bsize != bsize) 3911558Srgrimes printf("%s to be changed from %d to %d\n", 3921558Srgrimes "This requires the block size", 3931558Srgrimes bsize, sblock.fs_bsize); 3941558Srgrimes if (sblock.fs_fsize != fsize) 3951558Srgrimes printf("\t%s to be changed from %d to %d\n", 3961558Srgrimes "and the fragment size", 3971558Srgrimes fsize, sblock.fs_fsize); 3981558Srgrimes exit(23); 3991558Srgrimes } 4008871Srgrimes /* 4011558Srgrimes * Calculate the number of cylinders per group 4021558Srgrimes */ 4031558Srgrimes sblock.fs_cpg = cpg; 4041558Srgrimes if (sblock.fs_cpg % mincpc != 0) { 4051558Srgrimes printf("%s groups must have a multiple of %d cylinders\n", 4061558Srgrimes cpgflg ? "Cylinder" : "Warning: cylinder", mincpc); 4071558Srgrimes sblock.fs_cpg = roundup(sblock.fs_cpg, mincpc); 4081558Srgrimes if (!cpgflg) 4091558Srgrimes cpg = sblock.fs_cpg; 4101558Srgrimes } 4111558Srgrimes /* 4121558Srgrimes * Must ensure there is enough space for inodes. 4131558Srgrimes */ 4141558Srgrimes sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density, 4151558Srgrimes INOPB(&sblock)); 4161558Srgrimes while (sblock.fs_ipg > MAXIPG(&sblock)) { 4171558Srgrimes inodecramped = 1; 4181558Srgrimes sblock.fs_cpg -= mincpc; 4191558Srgrimes sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density, 4201558Srgrimes INOPB(&sblock)); 4211558Srgrimes } 4221558Srgrimes /* 4231558Srgrimes * Must ensure there is enough space to hold block map. 4241558Srgrimes */ 4251558Srgrimes while (CGSIZE(&sblock) > sblock.fs_bsize) { 4261558Srgrimes mapcramped = 1; 4271558Srgrimes sblock.fs_cpg -= mincpc; 4281558Srgrimes sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density, 4291558Srgrimes INOPB(&sblock)); 4301558Srgrimes } 4311558Srgrimes sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock); 4321558Srgrimes if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) { 4331558Srgrimes printf("panic (fs_cpg * fs_spc) % NSPF != 0"); 4341558Srgrimes exit(24); 4351558Srgrimes } 4361558Srgrimes if (sblock.fs_cpg < mincpg) { 4371558Srgrimes printf("cylinder groups must have at least %d cylinders\n", 4381558Srgrimes mincpg); 4391558Srgrimes exit(25); 4401558Srgrimes } else if (sblock.fs_cpg != cpg) { 4411558Srgrimes if (!cpgflg) 4421558Srgrimes printf("Warning: "); 4431558Srgrimes else if (!mapcramped && !inodecramped) 4441558Srgrimes exit(26); 4451558Srgrimes if (mapcramped && inodecramped) 4461558Srgrimes printf("Block size and bytes per inode restrict"); 4471558Srgrimes else if (mapcramped) 4481558Srgrimes printf("Block size restricts"); 4491558Srgrimes else 4501558Srgrimes printf("Bytes per inode restrict"); 4511558Srgrimes printf(" cylinders per group to %d.\n", sblock.fs_cpg); 4521558Srgrimes if (cpgflg) 4531558Srgrimes exit(27); 4541558Srgrimes } 4551558Srgrimes sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); 4561558Srgrimes /* 4571558Srgrimes * Now have size for file system and nsect and ntrak. 4581558Srgrimes * Determine number of cylinders and blocks in the file system. 4591558Srgrimes */ 4601558Srgrimes sblock.fs_size = fssize = dbtofsb(&sblock, fssize); 4611558Srgrimes sblock.fs_ncyl = fssize * NSPF(&sblock) / sblock.fs_spc; 4621558Srgrimes if (fssize * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) { 4631558Srgrimes sblock.fs_ncyl++; 4641558Srgrimes warn = 1; 4651558Srgrimes } 4661558Srgrimes if (sblock.fs_ncyl < 1) { 4671558Srgrimes printf("file systems must have at least one cylinder\n"); 4681558Srgrimes exit(28); 4691558Srgrimes } 4701558Srgrimes /* 4711558Srgrimes * Determine feasability/values of rotational layout tables. 4721558Srgrimes * 4731558Srgrimes * The size of the rotational layout tables is limited by the 4741558Srgrimes * size of the superblock, SBSIZE. The amount of space available 4751558Srgrimes * for tables is calculated as (SBSIZE - sizeof (struct fs)). 4761558Srgrimes * The size of these tables is inversely proportional to the block 4771558Srgrimes * size of the file system. The size increases if sectors per track 4781558Srgrimes * are not powers of two, because more cylinders must be described 4791558Srgrimes * by the tables before the rotational pattern repeats (fs_cpc). 4801558Srgrimes */ 4811558Srgrimes sblock.fs_interleave = interleave; 4821558Srgrimes sblock.fs_trackskew = trackskew; 4831558Srgrimes sblock.fs_npsect = nphyssectors; 4841558Srgrimes sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT; 4851558Srgrimes sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs)); 4863467Sdg if (sblock.fs_ntrak == 1) { 4871558Srgrimes sblock.fs_cpc = 0; 4881558Srgrimes goto next; 4891558Srgrimes } 4901558Srgrimes postblsize = sblock.fs_nrpos * sblock.fs_cpc * sizeof(short); 4911558Srgrimes rotblsize = sblock.fs_cpc * sblock.fs_spc / NSPB(&sblock); 4921558Srgrimes totalsbsize = sizeof(struct fs) + rotblsize; 4931558Srgrimes if (sblock.fs_nrpos == 8 && sblock.fs_cpc <= 16) { 4941558Srgrimes /* use old static table space */ 4951558Srgrimes sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) - 4961558Srgrimes (char *)(&sblock.fs_link); 4971558Srgrimes sblock.fs_rotbloff = &sblock.fs_space[0] - 4981558Srgrimes (u_char *)(&sblock.fs_link); 4991558Srgrimes } else { 5001558Srgrimes /* use dynamic table space */ 5011558Srgrimes sblock.fs_postbloff = &sblock.fs_space[0] - 5021558Srgrimes (u_char *)(&sblock.fs_link); 5031558Srgrimes sblock.fs_rotbloff = sblock.fs_postbloff + postblsize; 5041558Srgrimes totalsbsize += postblsize; 5051558Srgrimes } 5061558Srgrimes if (totalsbsize > SBSIZE || 5071558Srgrimes sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) { 5081558Srgrimes printf("%s %s %d %s %d.%s", 5091558Srgrimes "Warning: insufficient space in super block for\n", 5101558Srgrimes "rotational layout tables with nsect", sblock.fs_nsect, 5111558Srgrimes "and ntrak", sblock.fs_ntrak, 5121558Srgrimes "\nFile system performance may be impaired.\n"); 5131558Srgrimes sblock.fs_cpc = 0; 5141558Srgrimes goto next; 5151558Srgrimes } 5161558Srgrimes sblock.fs_sbsize = fragroundup(&sblock, totalsbsize); 5171558Srgrimes /* 5181558Srgrimes * calculate the available blocks for each rotational position 5191558Srgrimes */ 5201558Srgrimes for (cylno = 0; cylno < sblock.fs_cpc; cylno++) 5211558Srgrimes for (rpos = 0; rpos < sblock.fs_nrpos; rpos++) 5221558Srgrimes fs_postbl(&sblock, cylno)[rpos] = -1; 5231558Srgrimes for (i = (rotblsize - 1) * sblock.fs_frag; 5241558Srgrimes i >= 0; i -= sblock.fs_frag) { 5251558Srgrimes cylno = cbtocylno(&sblock, i); 5261558Srgrimes rpos = cbtorpos(&sblock, i); 5271558Srgrimes blk = fragstoblks(&sblock, i); 5281558Srgrimes if (fs_postbl(&sblock, cylno)[rpos] == -1) 5291558Srgrimes fs_rotbl(&sblock)[blk] = 0; 5301558Srgrimes else 5311558Srgrimes fs_rotbl(&sblock)[blk] = 5321558Srgrimes fs_postbl(&sblock, cylno)[rpos] - blk; 5331558Srgrimes fs_postbl(&sblock, cylno)[rpos] = blk; 5341558Srgrimes } 5351558Srgrimesnext: 5361558Srgrimes /* 5371558Srgrimes * Compute/validate number of cylinder groups. 5381558Srgrimes */ 5391558Srgrimes sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg; 5401558Srgrimes if (sblock.fs_ncyl % sblock.fs_cpg) 5411558Srgrimes sblock.fs_ncg++; 5421558Srgrimes sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); 5431558Srgrimes i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1); 5441558Srgrimes if (cgdmin(&sblock, i) - cgbase(&sblock, i) >= sblock.fs_fpg) { 5451558Srgrimes printf("inode blocks/cyl group (%d) >= data blocks (%d)\n", 5461558Srgrimes cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag, 5471558Srgrimes sblock.fs_fpg / sblock.fs_frag); 5481558Srgrimes printf("number of cylinders per cylinder group (%d) %s.\n", 5491558Srgrimes sblock.fs_cpg, "must be increased"); 5501558Srgrimes exit(29); 5511558Srgrimes } 5521558Srgrimes j = sblock.fs_ncg - 1; 5531558Srgrimes if ((i = fssize - j * sblock.fs_fpg) < sblock.fs_fpg && 5541558Srgrimes cgdmin(&sblock, j) - cgbase(&sblock, j) > i) { 5551558Srgrimes if (j == 0) { 5561558Srgrimes printf("Filesystem must have at least %d sectors\n", 5571558Srgrimes NSPF(&sblock) * 5581558Srgrimes (cgdmin(&sblock, 0) + 3 * sblock.fs_frag)); 5591558Srgrimes exit(30); 5601558Srgrimes } 5611558Srgrimes printf("Warning: inode blocks/cyl group (%d) >= data blocks (%d) in last\n", 5621558Srgrimes (cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag, 5631558Srgrimes i / sblock.fs_frag); 5641558Srgrimes printf(" cylinder group. This implies %d sector(s) cannot be allocated.\n", 5651558Srgrimes i * NSPF(&sblock)); 5661558Srgrimes sblock.fs_ncg--; 5671558Srgrimes sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg; 5681558Srgrimes sblock.fs_size = fssize = sblock.fs_ncyl * sblock.fs_spc / 5691558Srgrimes NSPF(&sblock); 5701558Srgrimes warn = 0; 5711558Srgrimes } 5721558Srgrimes if (warn && !mfs) { 5731558Srgrimes printf("Warning: %d sector(s) in last cylinder unallocated\n", 5741558Srgrimes sblock.fs_spc - 5751558Srgrimes (fssize * NSPF(&sblock) - (sblock.fs_ncyl - 1) 5761558Srgrimes * sblock.fs_spc)); 5771558Srgrimes } 5781558Srgrimes /* 5791558Srgrimes * fill in remaining fields of the super block 5801558Srgrimes */ 5811558Srgrimes sblock.fs_csaddr = cgdmin(&sblock, 0); 5821558Srgrimes sblock.fs_cssize = 5831558Srgrimes fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); 5841558Srgrimes i = sblock.fs_bsize / sizeof(struct csum); 5851558Srgrimes sblock.fs_csmask = ~(i - 1); 5861558Srgrimes for (sblock.fs_csshift = 0; i > 1; i >>= 1) 5871558Srgrimes sblock.fs_csshift++; 5881558Srgrimes fscs = (struct csum *)calloc(1, sblock.fs_cssize); 5891558Srgrimes sblock.fs_magic = FS_MAGIC; 5901558Srgrimes sblock.fs_rotdelay = rotdelay; 5911558Srgrimes sblock.fs_minfree = minfree; 5921558Srgrimes sblock.fs_maxcontig = maxcontig; 5931558Srgrimes sblock.fs_headswitch = headswitch; 5941558Srgrimes sblock.fs_trkseek = trackseek; 5951558Srgrimes sblock.fs_maxbpg = maxbpg; 5961558Srgrimes sblock.fs_rps = rpm / 60; 5971558Srgrimes sblock.fs_optim = opt; 5981558Srgrimes sblock.fs_cgrotor = 0; 5991558Srgrimes sblock.fs_cstotal.cs_ndir = 0; 6001558Srgrimes sblock.fs_cstotal.cs_nbfree = 0; 6011558Srgrimes sblock.fs_cstotal.cs_nifree = 0; 6021558Srgrimes sblock.fs_cstotal.cs_nffree = 0; 6031558Srgrimes sblock.fs_fmod = 0; 6041558Srgrimes sblock.fs_ronly = 0; 6052294Sdg sblock.fs_clean = 1; 6061558Srgrimes /* 6071558Srgrimes * Dump out summary information about file system. 6081558Srgrimes */ 6091558Srgrimes if (!mfs) { 6101558Srgrimes printf("%s:\t%d sectors in %d %s of %d tracks, %d sectors\n", 6111558Srgrimes fsys, sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl, 6121558Srgrimes "cylinders", sblock.fs_ntrak, sblock.fs_nsect); 6131558Srgrimes#define B2MBFACTOR (1 / (1024.0 * 1024.0)) 6141558Srgrimes printf("\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)\n", 6151558Srgrimes (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, 6161558Srgrimes sblock.fs_ncg, sblock.fs_cpg, 6171558Srgrimes (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, 6181558Srgrimes sblock.fs_ipg); 6191558Srgrimes#undef B2MBFACTOR 6201558Srgrimes } 6211558Srgrimes /* 6221558Srgrimes * Now build the cylinders group blocks and 6231558Srgrimes * then print out indices of cylinder groups. 6241558Srgrimes */ 6251558Srgrimes if (!mfs) 62613769Sjoerg printf("super-block backups (for fsck -b #) at:\n"); 62713769Sjoerg i = 0; 62813769Sjoerg width = charsperline(); 6291558Srgrimes for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { 6301558Srgrimes initcg(cylno, utime); 6311558Srgrimes if (mfs) 6321558Srgrimes continue; 63313769Sjoerg j = sprintf(tmpbuf, " %d,", 63413769Sjoerg fsbtodb(&sblock, cgsblock(&sblock, cylno))); 63513769Sjoerg if (i+j >= width) { 6361558Srgrimes printf("\n"); 63713769Sjoerg i = 0; 63813769Sjoerg } 63913769Sjoerg i += j; 64013769Sjoerg printf("%s", tmpbuf); 6418218Sdg fflush(stdout); 6421558Srgrimes } 6431558Srgrimes if (!mfs) 6441558Srgrimes printf("\n"); 6451558Srgrimes if (Nflag && !mfs) 6461558Srgrimes exit(0); 6471558Srgrimes /* 6481558Srgrimes * Now construct the initial file system, 6491558Srgrimes * then write out the super-block. 6501558Srgrimes */ 6511558Srgrimes fsinit(utime); 6521558Srgrimes sblock.fs_time = utime; 6531558Srgrimes wtfs((int)SBOFF / sectorsize, sbsize, (char *)&sblock); 6541558Srgrimes for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) 6551558Srgrimes wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), 6561558Srgrimes sblock.fs_cssize - i < sblock.fs_bsize ? 6571558Srgrimes sblock.fs_cssize - i : sblock.fs_bsize, 6581558Srgrimes ((char *)fscs) + i); 6598871Srgrimes /* 6601558Srgrimes * Write out the duplicate super blocks 6611558Srgrimes */ 6621558Srgrimes for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 6631558Srgrimes wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), 6641558Srgrimes sbsize, (char *)&sblock); 6651558Srgrimes /* 6661558Srgrimes * Update information about this partion in pack 6671558Srgrimes * label, to that it may be updated on disk. 6681558Srgrimes */ 6691558Srgrimes pp->p_fstype = FS_BSDFFS; 6701558Srgrimes pp->p_fsize = sblock.fs_fsize; 6711558Srgrimes pp->p_frag = sblock.fs_frag; 6721558Srgrimes pp->p_cpg = sblock.fs_cpg; 6731558Srgrimes /* 6741558Srgrimes * Notify parent process of success. 6751558Srgrimes * Dissociate from session and tty. 6761558Srgrimes */ 6771558Srgrimes if (mfs) { 6781558Srgrimes kill(ppid, SIGUSR1); 6791558Srgrimes (void) setsid(); 6801558Srgrimes (void) close(0); 6811558Srgrimes (void) close(1); 6821558Srgrimes (void) close(2); 6831558Srgrimes (void) chdir("/"); 6841558Srgrimes } 6851558Srgrimes} 6861558Srgrimes 6871558Srgrimes/* 6881558Srgrimes * Initialize a cylinder group. 6891558Srgrimes */ 6901558Srgrimesinitcg(cylno, utime) 6911558Srgrimes int cylno; 6921558Srgrimes time_t utime; 6931558Srgrimes{ 6941558Srgrimes daddr_t cbase, d, dlower, dupper, dmax, blkno; 6951558Srgrimes long i, j, s; 6961558Srgrimes register struct csum *cs; 6971558Srgrimes 6981558Srgrimes /* 6991558Srgrimes * Determine block bounds for cylinder group. 7001558Srgrimes * Allow space for super block summary information in first 7011558Srgrimes * cylinder group. 7021558Srgrimes */ 7031558Srgrimes cbase = cgbase(&sblock, cylno); 7041558Srgrimes dmax = cbase + sblock.fs_fpg; 7051558Srgrimes if (dmax > sblock.fs_size) 7061558Srgrimes dmax = sblock.fs_size; 7071558Srgrimes dlower = cgsblock(&sblock, cylno) - cbase; 7081558Srgrimes dupper = cgdmin(&sblock, cylno) - cbase; 7091558Srgrimes if (cylno == 0) 7101558Srgrimes dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 7111558Srgrimes cs = fscs + cylno; 7121558Srgrimes bzero(&acg, sblock.fs_cgsize); 7131558Srgrimes acg.cg_time = utime; 7141558Srgrimes acg.cg_magic = CG_MAGIC; 7151558Srgrimes acg.cg_cgx = cylno; 7161558Srgrimes if (cylno == sblock.fs_ncg - 1) 7171558Srgrimes acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg; 7181558Srgrimes else 7191558Srgrimes acg.cg_ncyl = sblock.fs_cpg; 7201558Srgrimes acg.cg_niblk = sblock.fs_ipg; 7211558Srgrimes acg.cg_ndblk = dmax - cbase; 7221558Srgrimes if (sblock.fs_contigsumsize > 0) 7231558Srgrimes acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; 7241558Srgrimes acg.cg_btotoff = &acg.cg_space[0] - (u_char *)(&acg.cg_link); 7251558Srgrimes acg.cg_boff = acg.cg_btotoff + sblock.fs_cpg * sizeof(long); 7268871Srgrimes acg.cg_iusedoff = acg.cg_boff + 7271558Srgrimes sblock.fs_cpg * sblock.fs_nrpos * sizeof(short); 7281558Srgrimes acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY); 7291558Srgrimes if (sblock.fs_contigsumsize <= 0) { 7301558Srgrimes acg.cg_nextfreeoff = acg.cg_freeoff + 7311558Srgrimes howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY); 7321558Srgrimes } else { 7331558Srgrimes acg.cg_clustersumoff = acg.cg_freeoff + howmany 7341558Srgrimes (sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY) - 7351558Srgrimes sizeof(long); 7361558Srgrimes acg.cg_clustersumoff = 7371558Srgrimes roundup(acg.cg_clustersumoff, sizeof(long)); 7381558Srgrimes acg.cg_clusteroff = acg.cg_clustersumoff + 7391558Srgrimes (sblock.fs_contigsumsize + 1) * sizeof(long); 7401558Srgrimes acg.cg_nextfreeoff = acg.cg_clusteroff + howmany 7411558Srgrimes (sblock.fs_cpg * sblock.fs_spc / NSPB(&sblock), NBBY); 7421558Srgrimes } 7431558Srgrimes if (acg.cg_nextfreeoff - (long)(&acg.cg_link) > sblock.fs_cgsize) { 7441558Srgrimes printf("Panic: cylinder group too big\n"); 7451558Srgrimes exit(37); 7461558Srgrimes } 7471558Srgrimes acg.cg_cs.cs_nifree += sblock.fs_ipg; 7481558Srgrimes if (cylno == 0) 7491558Srgrimes for (i = 0; i < ROOTINO; i++) { 7501558Srgrimes setbit(cg_inosused(&acg), i); 7511558Srgrimes acg.cg_cs.cs_nifree--; 7521558Srgrimes } 7531558Srgrimes for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag) 7541558Srgrimes wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), 7551558Srgrimes sblock.fs_bsize, (char *)zino); 7561558Srgrimes if (cylno > 0) { 7571558Srgrimes /* 7581558Srgrimes * In cylno 0, beginning space is reserved 7591558Srgrimes * for boot and super blocks. 7601558Srgrimes */ 7611558Srgrimes for (d = 0; d < dlower; d += sblock.fs_frag) { 7621558Srgrimes blkno = d / sblock.fs_frag; 7631558Srgrimes setblock(&sblock, cg_blksfree(&acg), blkno); 7641558Srgrimes if (sblock.fs_contigsumsize > 0) 7651558Srgrimes setbit(cg_clustersfree(&acg), blkno); 7661558Srgrimes acg.cg_cs.cs_nbfree++; 7671558Srgrimes cg_blktot(&acg)[cbtocylno(&sblock, d)]++; 7681558Srgrimes cg_blks(&sblock, &acg, cbtocylno(&sblock, d)) 7691558Srgrimes [cbtorpos(&sblock, d)]++; 7701558Srgrimes } 7711558Srgrimes sblock.fs_dsize += dlower; 7721558Srgrimes } 7731558Srgrimes sblock.fs_dsize += acg.cg_ndblk - dupper; 7741558Srgrimes if (i = dupper % sblock.fs_frag) { 7751558Srgrimes acg.cg_frsum[sblock.fs_frag - i]++; 7761558Srgrimes for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { 7771558Srgrimes setbit(cg_blksfree(&acg), dupper); 7781558Srgrimes acg.cg_cs.cs_nffree++; 7791558Srgrimes } 7801558Srgrimes } 7811558Srgrimes for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) { 7821558Srgrimes blkno = d / sblock.fs_frag; 7831558Srgrimes setblock(&sblock, cg_blksfree(&acg), blkno); 7841558Srgrimes if (sblock.fs_contigsumsize > 0) 7851558Srgrimes setbit(cg_clustersfree(&acg), blkno); 7861558Srgrimes acg.cg_cs.cs_nbfree++; 7871558Srgrimes cg_blktot(&acg)[cbtocylno(&sblock, d)]++; 7881558Srgrimes cg_blks(&sblock, &acg, cbtocylno(&sblock, d)) 7891558Srgrimes [cbtorpos(&sblock, d)]++; 7901558Srgrimes d += sblock.fs_frag; 7911558Srgrimes } 7921558Srgrimes if (d < dmax - cbase) { 7931558Srgrimes acg.cg_frsum[dmax - cbase - d]++; 7941558Srgrimes for (; d < dmax - cbase; d++) { 7951558Srgrimes setbit(cg_blksfree(&acg), d); 7961558Srgrimes acg.cg_cs.cs_nffree++; 7971558Srgrimes } 7981558Srgrimes } 7991558Srgrimes if (sblock.fs_contigsumsize > 0) { 8001558Srgrimes long *sump = cg_clustersum(&acg); 8011558Srgrimes u_char *mapp = cg_clustersfree(&acg); 8021558Srgrimes int map = *mapp++; 8031558Srgrimes int bit = 1; 8041558Srgrimes int run = 0; 8051558Srgrimes 8061558Srgrimes for (i = 0; i < acg.cg_nclusterblks; i++) { 8071558Srgrimes if ((map & bit) != 0) { 8081558Srgrimes run++; 8091558Srgrimes } else if (run != 0) { 8101558Srgrimes if (run > sblock.fs_contigsumsize) 8111558Srgrimes run = sblock.fs_contigsumsize; 8121558Srgrimes sump[run]++; 8131558Srgrimes run = 0; 8141558Srgrimes } 8151558Srgrimes if ((i & (NBBY - 1)) != (NBBY - 1)) { 8161558Srgrimes bit <<= 1; 8171558Srgrimes } else { 8181558Srgrimes map = *mapp++; 8191558Srgrimes bit = 1; 8201558Srgrimes } 8211558Srgrimes } 8221558Srgrimes if (run != 0) { 8231558Srgrimes if (run > sblock.fs_contigsumsize) 8241558Srgrimes run = sblock.fs_contigsumsize; 8251558Srgrimes sump[run]++; 8261558Srgrimes } 8271558Srgrimes } 8281558Srgrimes sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir; 8291558Srgrimes sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree; 8301558Srgrimes sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree; 8311558Srgrimes sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree; 8321558Srgrimes *cs = acg.cg_cs; 8331558Srgrimes wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), 8341558Srgrimes sblock.fs_bsize, (char *)&acg); 8351558Srgrimes} 8361558Srgrimes 8371558Srgrimes/* 8381558Srgrimes * initialize the file system 8391558Srgrimes */ 8401558Srgrimesstruct dinode node; 8411558Srgrimes 8421558Srgrimes#ifdef LOSTDIR 8431558Srgrimes#define PREDEFDIR 3 8441558Srgrimes#else 8451558Srgrimes#define PREDEFDIR 2 8461558Srgrimes#endif 8471558Srgrimes 8481558Srgrimesstruct direct root_dir[] = { 8491558Srgrimes { ROOTINO, sizeof(struct direct), DT_DIR, 1, "." }, 8501558Srgrimes { ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." }, 8511558Srgrimes#ifdef LOSTDIR 8521558Srgrimes { LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 10, "lost+found" }, 8531558Srgrimes#endif 8541558Srgrimes}; 8551558Srgrimesstruct odirect { 8561558Srgrimes u_long d_ino; 8571558Srgrimes u_short d_reclen; 8581558Srgrimes u_short d_namlen; 8591558Srgrimes u_char d_name[MAXNAMLEN + 1]; 8601558Srgrimes} oroot_dir[] = { 8611558Srgrimes { ROOTINO, sizeof(struct direct), 1, "." }, 8621558Srgrimes { ROOTINO, sizeof(struct direct), 2, ".." }, 8631558Srgrimes#ifdef LOSTDIR 8641558Srgrimes { LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found" }, 8651558Srgrimes#endif 8661558Srgrimes}; 8671558Srgrimes#ifdef LOSTDIR 8681558Srgrimesstruct direct lost_found_dir[] = { 8691558Srgrimes { LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 1, "." }, 8701558Srgrimes { ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." }, 8711558Srgrimes { 0, DIRBLKSIZ, 0, 0, 0 }, 8721558Srgrimes}; 8731558Srgrimesstruct odirect olost_found_dir[] = { 8741558Srgrimes { LOSTFOUNDINO, sizeof(struct direct), 1, "." }, 8751558Srgrimes { ROOTINO, sizeof(struct direct), 2, ".." }, 8761558Srgrimes { 0, DIRBLKSIZ, 0, 0 }, 8771558Srgrimes}; 8781558Srgrimes#endif 8791558Srgrimeschar buf[MAXBSIZE]; 8801558Srgrimes 8811558Srgrimesfsinit(utime) 8821558Srgrimes time_t utime; 8831558Srgrimes{ 8841558Srgrimes int i; 8851558Srgrimes 8861558Srgrimes /* 8871558Srgrimes * initialize the node 8881558Srgrimes */ 8891558Srgrimes node.di_atime.ts_sec = utime; 8901558Srgrimes node.di_mtime.ts_sec = utime; 8911558Srgrimes node.di_ctime.ts_sec = utime; 8921558Srgrimes#ifdef LOSTDIR 8931558Srgrimes /* 8941558Srgrimes * create the lost+found directory 8951558Srgrimes */ 8961558Srgrimes if (Oflag) { 8971558Srgrimes (void)makedir((struct direct *)olost_found_dir, 2); 8981558Srgrimes for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ) 8991558Srgrimes bcopy(&olost_found_dir[2], &buf[i], 9001558Srgrimes DIRSIZ(0, &olost_found_dir[2])); 9011558Srgrimes } else { 9021558Srgrimes (void)makedir(lost_found_dir, 2); 9031558Srgrimes for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ) 9041558Srgrimes bcopy(&lost_found_dir[2], &buf[i], 9051558Srgrimes DIRSIZ(0, &lost_found_dir[2])); 9061558Srgrimes } 9071558Srgrimes node.di_mode = IFDIR | UMASK; 9081558Srgrimes node.di_nlink = 2; 9091558Srgrimes node.di_size = sblock.fs_bsize; 9101558Srgrimes node.di_db[0] = alloc(node.di_size, node.di_mode); 9111558Srgrimes node.di_blocks = btodb(fragroundup(&sblock, node.di_size)); 9121558Srgrimes wtfs(fsbtodb(&sblock, node.di_db[0]), node.di_size, buf); 9131558Srgrimes iput(&node, LOSTFOUNDINO); 9141558Srgrimes#endif 9151558Srgrimes /* 9161558Srgrimes * create the root directory 9171558Srgrimes */ 9181558Srgrimes if (mfs) 9191558Srgrimes node.di_mode = IFDIR | 01777; 9201558Srgrimes else 9211558Srgrimes node.di_mode = IFDIR | UMASK; 9221558Srgrimes node.di_nlink = PREDEFDIR; 9231558Srgrimes if (Oflag) 9241558Srgrimes node.di_size = makedir((struct direct *)oroot_dir, PREDEFDIR); 9251558Srgrimes else 9261558Srgrimes node.di_size = makedir(root_dir, PREDEFDIR); 9271558Srgrimes node.di_db[0] = alloc(sblock.fs_fsize, node.di_mode); 9281558Srgrimes node.di_blocks = btodb(fragroundup(&sblock, node.di_size)); 9291558Srgrimes wtfs(fsbtodb(&sblock, node.di_db[0]), sblock.fs_fsize, buf); 9301558Srgrimes iput(&node, ROOTINO); 9311558Srgrimes} 9321558Srgrimes 9331558Srgrimes/* 9341558Srgrimes * construct a set of directory entries in "buf". 9351558Srgrimes * return size of directory. 9361558Srgrimes */ 9371558Srgrimesmakedir(protodir, entries) 9381558Srgrimes register struct direct *protodir; 9391558Srgrimes int entries; 9401558Srgrimes{ 9411558Srgrimes char *cp; 9421558Srgrimes int i, spcleft; 9431558Srgrimes 9441558Srgrimes spcleft = DIRBLKSIZ; 9451558Srgrimes for (cp = buf, i = 0; i < entries - 1; i++) { 9461558Srgrimes protodir[i].d_reclen = DIRSIZ(0, &protodir[i]); 9471558Srgrimes bcopy(&protodir[i], cp, protodir[i].d_reclen); 9481558Srgrimes cp += protodir[i].d_reclen; 9491558Srgrimes spcleft -= protodir[i].d_reclen; 9501558Srgrimes } 9511558Srgrimes protodir[i].d_reclen = spcleft; 9521558Srgrimes bcopy(&protodir[i], cp, DIRSIZ(0, &protodir[i])); 9531558Srgrimes return (DIRBLKSIZ); 9541558Srgrimes} 9551558Srgrimes 9561558Srgrimes/* 9571558Srgrimes * allocate a block or frag 9581558Srgrimes */ 9591558Srgrimesdaddr_t 9601558Srgrimesalloc(size, mode) 9611558Srgrimes int size; 9621558Srgrimes int mode; 9631558Srgrimes{ 9641558Srgrimes int i, frag; 9651558Srgrimes daddr_t d, blkno; 9661558Srgrimes 9671558Srgrimes rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, 9681558Srgrimes (char *)&acg); 9691558Srgrimes if (acg.cg_magic != CG_MAGIC) { 9701558Srgrimes printf("cg 0: bad magic number\n"); 9711558Srgrimes return (0); 9721558Srgrimes } 9731558Srgrimes if (acg.cg_cs.cs_nbfree == 0) { 9741558Srgrimes printf("first cylinder group ran out of space\n"); 9751558Srgrimes return (0); 9761558Srgrimes } 9771558Srgrimes for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag) 9781558Srgrimes if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag)) 9791558Srgrimes goto goth; 9801558Srgrimes printf("internal error: can't find block in cyl 0\n"); 9811558Srgrimes return (0); 9821558Srgrimesgoth: 9831558Srgrimes blkno = fragstoblks(&sblock, d); 9841558Srgrimes clrblock(&sblock, cg_blksfree(&acg), blkno); 9851558Srgrimes clrbit(cg_clustersfree(&acg), blkno); 9861558Srgrimes acg.cg_cs.cs_nbfree--; 9871558Srgrimes sblock.fs_cstotal.cs_nbfree--; 9881558Srgrimes fscs[0].cs_nbfree--; 9891558Srgrimes if (mode & IFDIR) { 9901558Srgrimes acg.cg_cs.cs_ndir++; 9911558Srgrimes sblock.fs_cstotal.cs_ndir++; 9921558Srgrimes fscs[0].cs_ndir++; 9931558Srgrimes } 9941558Srgrimes cg_blktot(&acg)[cbtocylno(&sblock, d)]--; 9951558Srgrimes cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--; 9961558Srgrimes if (size != sblock.fs_bsize) { 9971558Srgrimes frag = howmany(size, sblock.fs_fsize); 9981558Srgrimes fscs[0].cs_nffree += sblock.fs_frag - frag; 9991558Srgrimes sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag; 10001558Srgrimes acg.cg_cs.cs_nffree += sblock.fs_frag - frag; 10011558Srgrimes acg.cg_frsum[sblock.fs_frag - frag]++; 10021558Srgrimes for (i = frag; i < sblock.fs_frag; i++) 10031558Srgrimes setbit(cg_blksfree(&acg), d + i); 10041558Srgrimes } 10051558Srgrimes wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, 10061558Srgrimes (char *)&acg); 10071558Srgrimes return (d); 10081558Srgrimes} 10091558Srgrimes 10101558Srgrimes/* 10111558Srgrimes * Allocate an inode on the disk 10121558Srgrimes */ 10131558Srgrimesiput(ip, ino) 10141558Srgrimes register struct dinode *ip; 10151558Srgrimes register ino_t ino; 10161558Srgrimes{ 10171558Srgrimes struct dinode buf[MAXINOPB]; 10181558Srgrimes daddr_t d; 10191558Srgrimes int c; 10201558Srgrimes 10211558Srgrimes c = ino_to_cg(&sblock, ino); 10221558Srgrimes rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, 10231558Srgrimes (char *)&acg); 10241558Srgrimes if (acg.cg_magic != CG_MAGIC) { 10251558Srgrimes printf("cg 0: bad magic number\n"); 10261558Srgrimes exit(31); 10271558Srgrimes } 10281558Srgrimes acg.cg_cs.cs_nifree--; 10291558Srgrimes setbit(cg_inosused(&acg), ino); 10301558Srgrimes wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, 10311558Srgrimes (char *)&acg); 10321558Srgrimes sblock.fs_cstotal.cs_nifree--; 10331558Srgrimes fscs[0].cs_nifree--; 10341558Srgrimes if (ino >= sblock.fs_ipg * sblock.fs_ncg) { 10351558Srgrimes printf("fsinit: inode value out of range (%d).\n", ino); 10361558Srgrimes exit(32); 10371558Srgrimes } 10381558Srgrimes d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino)); 10391558Srgrimes rdfs(d, sblock.fs_bsize, buf); 10401558Srgrimes buf[ino_to_fsbo(&sblock, ino)] = *ip; 10411558Srgrimes wtfs(d, sblock.fs_bsize, buf); 10421558Srgrimes} 10431558Srgrimes 10441558Srgrimes/* 10451558Srgrimes * Notify parent process that the filesystem has created itself successfully. 10461558Srgrimes */ 10471558Srgrimesvoid 10481558Srgrimesstarted() 10491558Srgrimes{ 10501558Srgrimes 10511558Srgrimes exit(0); 10521558Srgrimes} 10531558Srgrimes 10541558Srgrimes/* 10551558Srgrimes * Replace libc function with one suited to our needs. 10561558Srgrimes */ 10571558Srgrimescaddr_t 10581558Srgrimesmalloc(size) 10591558Srgrimes register u_long size; 10601558Srgrimes{ 10611558Srgrimes char *base, *i; 10621558Srgrimes static u_long pgsz; 10631558Srgrimes struct rlimit rlp; 10641558Srgrimes 10651558Srgrimes if (pgsz == 0) { 10661558Srgrimes base = sbrk(0); 10671558Srgrimes pgsz = getpagesize() - 1; 10681558Srgrimes i = (char *)((u_long)(base + pgsz) &~ pgsz); 10691558Srgrimes base = sbrk(i - base); 10701558Srgrimes if (getrlimit(RLIMIT_DATA, &rlp) < 0) 10711558Srgrimes perror("getrlimit"); 10721558Srgrimes rlp.rlim_cur = rlp.rlim_max; 10731558Srgrimes if (setrlimit(RLIMIT_DATA, &rlp) < 0) 10741558Srgrimes perror("setrlimit"); 10751558Srgrimes memleft = rlp.rlim_max - (u_long)base; 10761558Srgrimes } 10771558Srgrimes size = (size + pgsz) &~ pgsz; 10781558Srgrimes if (size > memleft) 10791558Srgrimes size = memleft; 10801558Srgrimes memleft -= size; 10811558Srgrimes if (size == 0) 10821558Srgrimes return (0); 10831558Srgrimes return ((caddr_t)sbrk(size)); 10841558Srgrimes} 10851558Srgrimes 10861558Srgrimes/* 10871558Srgrimes * Replace libc function with one suited to our needs. 10881558Srgrimes */ 10891558Srgrimescaddr_t 10901558Srgrimesrealloc(ptr, size) 10911558Srgrimes char *ptr; 10921558Srgrimes u_long size; 10931558Srgrimes{ 10941558Srgrimes void *p; 10951558Srgrimes 10961558Srgrimes if ((p = malloc(size)) == NULL) 10971558Srgrimes return (NULL); 10981558Srgrimes bcopy(ptr, p, size); 10991558Srgrimes free(ptr); 11001558Srgrimes return (p); 11011558Srgrimes} 11021558Srgrimes 11031558Srgrimes/* 11041558Srgrimes * Replace libc function with one suited to our needs. 11051558Srgrimes */ 11061558Srgrimeschar * 11071558Srgrimescalloc(size, numelm) 11081558Srgrimes u_long size, numelm; 11091558Srgrimes{ 11101558Srgrimes caddr_t base; 11111558Srgrimes 11121558Srgrimes size *= numelm; 11131558Srgrimes base = malloc(size); 11141558Srgrimes bzero(base, size); 11151558Srgrimes return (base); 11161558Srgrimes} 11171558Srgrimes 11181558Srgrimes/* 11191558Srgrimes * Replace libc function with one suited to our needs. 11201558Srgrimes */ 11211558Srgrimesfree(ptr) 11221558Srgrimes char *ptr; 11231558Srgrimes{ 11248871Srgrimes 11251558Srgrimes /* do not worry about it for now */ 11261558Srgrimes} 11271558Srgrimes 11281558Srgrimes/* 11291558Srgrimes * read a block from the file system 11301558Srgrimes */ 11311558Srgrimesrdfs(bno, size, bf) 11321558Srgrimes daddr_t bno; 11331558Srgrimes int size; 11341558Srgrimes char *bf; 11351558Srgrimes{ 11361558Srgrimes int n; 11371558Srgrimes 11381558Srgrimes if (mfs) { 11391558Srgrimes bcopy(membase + bno * sectorsize, bf, size); 11401558Srgrimes return; 11411558Srgrimes } 11421558Srgrimes if (lseek(fsi, (off_t)bno * sectorsize, 0) < 0) { 11431558Srgrimes printf("seek error: %ld\n", bno); 11441558Srgrimes perror("rdfs"); 11451558Srgrimes exit(33); 11461558Srgrimes } 11471558Srgrimes n = read(fsi, bf, size); 11481558Srgrimes if (n != size) { 11491558Srgrimes printf("read error: %ld\n", bno); 11501558Srgrimes perror("rdfs"); 11511558Srgrimes exit(34); 11521558Srgrimes } 11531558Srgrimes} 11541558Srgrimes 11551558Srgrimes/* 11561558Srgrimes * write a block to the file system 11571558Srgrimes */ 11581558Srgrimeswtfs(bno, size, bf) 11591558Srgrimes daddr_t bno; 11601558Srgrimes int size; 11611558Srgrimes char *bf; 11621558Srgrimes{ 11631558Srgrimes int n; 11641558Srgrimes 11651558Srgrimes if (mfs) { 11661558Srgrimes bcopy(bf, membase + bno * sectorsize, size); 11671558Srgrimes return; 11681558Srgrimes } 11691558Srgrimes if (Nflag) 11701558Srgrimes return; 11711558Srgrimes if (lseek(fso, (off_t)bno * sectorsize, SEEK_SET) < 0) { 11721558Srgrimes printf("seek error: %ld\n", bno); 11731558Srgrimes perror("wtfs"); 11741558Srgrimes exit(35); 11751558Srgrimes } 11761558Srgrimes n = write(fso, bf, size); 11771558Srgrimes if (n != size) { 11781558Srgrimes printf("write error: %ld\n", bno); 11791558Srgrimes perror("wtfs"); 11801558Srgrimes exit(36); 11811558Srgrimes } 11821558Srgrimes} 11831558Srgrimes 11841558Srgrimes/* 11851558Srgrimes * check if a block is available 11861558Srgrimes */ 11871558Srgrimesisblock(fs, cp, h) 11881558Srgrimes struct fs *fs; 11891558Srgrimes unsigned char *cp; 11901558Srgrimes int h; 11911558Srgrimes{ 11921558Srgrimes unsigned char mask; 11931558Srgrimes 11941558Srgrimes switch (fs->fs_frag) { 11951558Srgrimes case 8: 11961558Srgrimes return (cp[h] == 0xff); 11971558Srgrimes case 4: 11981558Srgrimes mask = 0x0f << ((h & 0x1) << 2); 11991558Srgrimes return ((cp[h >> 1] & mask) == mask); 12001558Srgrimes case 2: 12011558Srgrimes mask = 0x03 << ((h & 0x3) << 1); 12021558Srgrimes return ((cp[h >> 2] & mask) == mask); 12031558Srgrimes case 1: 12041558Srgrimes mask = 0x01 << (h & 0x7); 12051558Srgrimes return ((cp[h >> 3] & mask) == mask); 12061558Srgrimes default: 12071558Srgrimes#ifdef STANDALONE 12081558Srgrimes printf("isblock bad fs_frag %d\n", fs->fs_frag); 12091558Srgrimes#else 12101558Srgrimes fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag); 12111558Srgrimes#endif 12121558Srgrimes return (0); 12131558Srgrimes } 12141558Srgrimes} 12151558Srgrimes 12161558Srgrimes/* 12171558Srgrimes * take a block out of the map 12181558Srgrimes */ 12191558Srgrimesclrblock(fs, cp, h) 12201558Srgrimes struct fs *fs; 12211558Srgrimes unsigned char *cp; 12221558Srgrimes int h; 12231558Srgrimes{ 12241558Srgrimes switch ((fs)->fs_frag) { 12251558Srgrimes case 8: 12261558Srgrimes cp[h] = 0; 12271558Srgrimes return; 12281558Srgrimes case 4: 12291558Srgrimes cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 12301558Srgrimes return; 12311558Srgrimes case 2: 12321558Srgrimes cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 12331558Srgrimes return; 12341558Srgrimes case 1: 12351558Srgrimes cp[h >> 3] &= ~(0x01 << (h & 0x7)); 12361558Srgrimes return; 12371558Srgrimes default: 12381558Srgrimes#ifdef STANDALONE 12391558Srgrimes printf("clrblock bad fs_frag %d\n", fs->fs_frag); 12401558Srgrimes#else 12411558Srgrimes fprintf(stderr, "clrblock bad fs_frag %d\n", fs->fs_frag); 12421558Srgrimes#endif 12431558Srgrimes return; 12441558Srgrimes } 12451558Srgrimes} 12461558Srgrimes 12471558Srgrimes/* 12481558Srgrimes * put a block into the map 12491558Srgrimes */ 12501558Srgrimessetblock(fs, cp, h) 12511558Srgrimes struct fs *fs; 12521558Srgrimes unsigned char *cp; 12531558Srgrimes int h; 12541558Srgrimes{ 12551558Srgrimes switch (fs->fs_frag) { 12561558Srgrimes case 8: 12571558Srgrimes cp[h] = 0xff; 12581558Srgrimes return; 12591558Srgrimes case 4: 12601558Srgrimes cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 12611558Srgrimes return; 12621558Srgrimes case 2: 12631558Srgrimes cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 12641558Srgrimes return; 12651558Srgrimes case 1: 12661558Srgrimes cp[h >> 3] |= (0x01 << (h & 0x7)); 12671558Srgrimes return; 12681558Srgrimes default: 12691558Srgrimes#ifdef STANDALONE 12701558Srgrimes printf("setblock bad fs_frag %d\n", fs->fs_frag); 12711558Srgrimes#else 12721558Srgrimes fprintf(stderr, "setblock bad fs_frag %d\n", fs->fs_frag); 12731558Srgrimes#endif 12741558Srgrimes return; 12751558Srgrimes } 12761558Srgrimes} 127713637Sjoerg 127813637Sjoerg/* 127913769Sjoerg * Determine the number of characters in a 128013637Sjoerg * single line. 128113637Sjoerg */ 128213637Sjoerg 128313637Sjoergstatic int 128413769Sjoergcharsperline() 128513637Sjoerg{ 128613769Sjoerg int columns; 128713637Sjoerg char *cp; 128813637Sjoerg struct winsize ws; 128913637Sjoerg extern char *getenv(); 129013637Sjoerg 129113637Sjoerg columns = 0; 129213637Sjoerg if (ioctl(0, TIOCGWINSZ, &ws) != -1) 129313637Sjoerg columns = ws.ws_col; 129413637Sjoerg if (columns == 0 && (cp = getenv("COLUMNS"))) 129513637Sjoerg columns = atoi(cp); 129613637Sjoerg if (columns == 0) 129713637Sjoerg columns = 80; /* last resort */ 129813769Sjoerg return columns; 129913637Sjoerg} 1300