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