date and time created 81/08/26 23:47:31 by mckusick
[unix-history] / usr / src / sbin / newfs / mkfs.c
static char *sccsid = "@(#)mkfs.c 1.1 (Berkeley) %G%";
/*
* make file system for cylinder-group style file systems
*
* usage: mkfs fs proto
* or: mkfs size [ nsect ntrak cpg ]
*/
#define NDIRECT (BSIZE/sizeof(struct direct))
#define MAXFN 500
#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
#ifndef STANDALONE
#include <stdio.h>
#include <a.out.h>
#endif
#include "../h/param.h"
#include "../h/ino.h"
#include "../h/inode.h"
#include "../h/fs.h"
#include "../h/dir.h"
time_t utime;
#ifndef STANDALONE
FILE *fin;
#else
int fin;
#endif
int fsi;
int fso;
char *charp;
char buf[BSIZE];
#ifndef STANDALONE
struct exec head;
#endif
char string[50];
union {
struct fs fs;
char pad[BSIZE];
} fsun;
#define sblock fsun.fs
struct csum *fscs;
union {
struct cg cg;
char pad[BSIZE];
} cgun;
#define acg cgun.cg
#define howmany(x, y) (((x)+((y)-1))/(y))
#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
char *fsys;
char *proto;
int error;
ino_t ino = ROOTINO - 1;
long getnum();
daddr_t alloc();
struct dinode zino[MAXIPG];
main(argc, argv)
char *argv[];
{
int f, c;
long i,n;
argc--, argv++;
#ifndef STANDALONE
time(&utime);
if(argc < 2) {
printf("usage: mkfs sblock proto/size [ nsect ntrak cpg ]\n");
exit(1);
}
fsys = argv[0];
proto = argv[1];
#else
{
static char protos[60];
printf("file sys size: ");
gets(protos);
proto = protos;
}
#endif
#ifdef STANDALONE
{
char fsbuf[100];
do {
printf("file system: ");
gets(fsbuf);
fso = open(fsbuf, 1);
fsi = open(fsbuf, 0);
} while (fso < 0 || fsi < 0);
}
fin = NULL;
argc = 0;
#else
fso = creat(fsys, 0666);
if(fso < 0) {
printf("%s: cannot create\n", fsys);
exit(1);
}
fsi = open(fsys, 0);
if(fsi < 0) {
printf("%s: cannot open\n", fsys);
exit(1);
}
fin = fopen(proto, "r");
#endif
#ifndef STANDALONE
if (fin != NULL) {
getstr();
f = open(string, 0);
if (f < 0) {
printf("%s: cannot open init\n", string);
goto noinit;
}
read(f, (char *)&head, sizeof head);
c = head.a_text + head.a_data;
if (c > BSIZE)
printf("%s: too big\n", string);
else {
read(f, buf, c);
wtfs(BBLOCK, BSIZE, buf);
}
close(f);
noinit:
n = sblock.fs_size = getnum();
sblock.fs_ntrak = getnum();
sblock.fs_nsect = getnum();
sblock.fs_cpg = getnum();
} else
#endif
{
charp = "d--777 0 0 $ ";
n = 0;
for (f=0; c=proto[f]; f++) {
if (c<'0' || c>'9') {
printf("%s: cannot open\n", proto);
exit(1);
}
n = n*10 + (c-'0');
}
sblock.fs_size = n;
if (argc > 2)
sblock.fs_nsect = atoi(argv[2]);
else
sblock.fs_nsect = 32;
if (argc > 3)
sblock.fs_ntrak = atoi(argv[3]);
else
sblock.fs_ntrak = 19;
}
/*
* Now have size for file system and nsect and ntrak.
* (And, if coming from prototype, cpg).
* Determine number of cylinders occupied by file system.
*/
if (sblock.fs_ntrak <= 0)
printf("preposterous ntrak %d\n", sblock.fs_ntrak), exit(1);
if (sblock.fs_nsect <= 0)
printf("preposterous nsect %d\n", sblock.fs_nsect), exit(1);
if (sblock.fs_size <= 0)
printf("preposterous size %d\n", sblock.fs_size), exit(1);
if (sblock.fs_ntrak * sblock.fs_nsect > MAXBPG * NSPB) {
printf("cylinder too large (%d sectors)\n",
sblock.fs_ntrak * sblock.fs_nsect);
printf("maximum cylinder size: %d sectors\n",
MAXBPG * NSPB);
exit(1);
}
sblock.fs_ncyl = n * NSPF / (sblock.fs_nsect * sblock.fs_ntrak);
if (n * NSPF > sblock.fs_ncyl * sblock.fs_nsect * sblock.fs_ntrak) {
printf("%d sector(s) in last cylinder unused\n",
n * NSPF - sblock.fs_ncyl * sblock.fs_nsect * sblock.fs_ntrak);
sblock.fs_ncyl++;
}
sblock.fs_magic = FS_MAGIC;
/*
* Validate specified/determined cpg.
*/
#define CGTOOBIG(fs) ((fs).fs_nsect*(fs).fs_ntrak*(fs).fs_cpg/NSPB > MAXBPG)
if (argc > 4 || fin) {
if (fin == NULL)
sblock.fs_cpg = atoi(argv[4]);
if (CGTOOBIG(sblock)) {
printf("cylinder group too large (%d blocks); ",
sblock.fs_cpg * sblock.fs_nsect * sblock.fs_ntrak / NSPB);
printf("max: %d blocks\n", MAXBPG);
exit(1);
}
if (sblock.fs_cpg > MAXCPG) {
printf("cylinder groups are limited to %d cylinders\n",
MAXCPG);
exit(1);
}
} else {
sblock.fs_cpg = DESCPG;
while (CGTOOBIG(sblock))
--sblock.fs_cpg;
}
/*
* Compute/validate number of cylinder groups.
*/
sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
if (sblock.fs_ncyl % sblock.fs_cpg)
sblock.fs_ncg++;
if ((sblock.fs_nsect*sblock.fs_ntrak*sblock.fs_cpg) % NSPF) {
printf("mkfs: nsect %d, ntrak %d, cpg %d is not tolerable\n",
sblock.fs_nsect, sblock.fs_ntrak, sblock.fs_cpg);
printf("as this would would have cyl groups whose size\n");
printf("is not a multiple of %d; choke!\n", FSIZE);
exit(1);
}
fscs = (struct csum *)
calloc(1, roundup(sblock.fs_ncg * sizeof (struct csum), BSIZE));
/*
* Compute number of inode blocks per cylinder group.
* Start with one inode per NBPI bytes; adjust as necessary.
*/
n = ((n * BSIZE) / NBPI) / INOPB;
if (n <= 0)
n = 1;
if (n > 65500/INOPB)
n = 65500/INOPB;
sblock.fs_ipg = ((n / sblock.fs_ncg) + 1) * INOPB;
if (sblock.fs_ipg < INOPB)
sblock.fs_ipg = INOPB;
if (sblock.fs_ipg > MAXIPG)
sblock.fs_ipg = MAXIPG;
while (sblock.fs_ipg * sblock.fs_ncyl > 65500)
sblock.fs_ipg -= INOPB;
sblock.fs_spc = sblock.fs_ntrak * sblock.fs_nsect;
sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / (FSIZE / 512);
if (cgdmin(0,&sblock) >= sblock.fs_fpg)
printf("inode blocks/cyl group (%d) >= data blocks (%d)\n",
cgdmin(0,&sblock)/FRAG, sblock.fs_fpg/FRAG), exit(1);
sblock.fs_nifree = sblock.fs_ipg * sblock.fs_ncg;
sblock.fs_cgsize = cgsize(&sblock);
sblock.fs_cssize = cssize(&sblock);
sblock.fs_sblkno = SBLOCK;
sblock.fs_fmod = 0;
sblock.fs_ronly = 0;
/*
* Dump out information about file system.
*/
printf("%s:\t%d sectors in %d cylinders of %d tracks, %d sectors\n",
fsys, sblock.fs_size*NSPF, sblock.fs_ncyl, sblock.fs_ntrak, sblock.fs_nsect);
printf("\t%.1fMb in %d cyl groups (%d c/g, %.2fMb/g, %d i/g)\n",
(float)sblock.fs_size*FSIZE*1e-6, sblock.fs_ncg, sblock.fs_cpg,
(float)sblock.fs_fpg*FSIZE*1e-6, sblock.fs_ipg);
/*
printf("%7d size (%d blocks)\n", sblock.fs_size, sblock.fs_size/FRAG);
printf("%7d cylinder groups\n", sblock.fs_ncg);
printf("%7d cylinder group block size\n", sblock.fs_cgsize);
printf("%7d tracks\n", sblock.fs_ntrak);
printf("%7d sectors\n", sblock.fs_nsect);
printf("%7d sectors per cylinder\n", sblock.fs_spc);
printf("%7d cylinders\n", sblock.fs_ncyl);
printf("%7d cylinders per group\n", sblock.fs_cpg);
printf("%7d blocks per group\n", sblock.fs_fpg/FRAG);
printf("%7d inodes per group\n", sblock.fs_ipg);
if (sblock.fs_ncyl % sblock.fs_cpg) {
printf("%7d cylinders in last group\n",
i = sblock.fs_ncyl % sblock.fs_cpg);
printf("%7d blocks in last group\n",
i * sblock.fs_spc / NSPB);
}
*/
/*
* Now build the cylinders group blocks and
* then print out indices of cylinder groups forwarded
* past bad blocks or other obstructions.
*/
sblock.fs_nffree = 0;
sblock.fs_nbfree = 0;
for (c = 0; c < sblock.fs_ncg; c++)
initcg(c);
printf("\tsuper-block backups (for fsck -b#) at %d+k*%d (%d .. %d)\n",
SBLOCK, sblock.fs_fpg, SBLOCK+sblock.fs_fpg,
SBLOCK+(sblock.fs_ncg-1)*sblock.fs_fpg);
/*
* Now construct the initial file system, and
* then write out the super-block.
*/
cfile((struct inode *)0);
sblock.fs_time = utime;
wtfs(SBLOCK, BSIZE, (char *)&sblock);
for (i = 0; i < cssize(&sblock); i += BSIZE)
wtfs(csaddr(&sblock) + i/BSIZE, BSIZE, ((char *)fscs)+i);
for (c = 0; c < sblock.fs_ncg; c++)
wtfs(cgsblock(c, &sblock), BSIZE, (char *)&sblock);
#ifndef STANDALONE
exit(error);
#endif
}
/*
* Initialize a cylinder group.
*/
initcg(c)
int c;
{
daddr_t cbase, d, dmin, dmax;
long i, j, s;
register struct csum *cs;
/*
* Determine block bounds for cylinder group.
* Allow space for super block summary information in first
* cylinder group.
*/
cbase = cgbase(c,&sblock);
dmax = cbase + sblock.fs_fpg;
if (dmax > sblock.fs_size)
dmax = sblock.fs_size;
d = cbase;
cs = fscs+c;
tryagain:
for (i = cgdmin(c,&sblock) - FRAG; i >= 0; i -= FRAG)
if (badblk(d)) {
d += i + FRAG;
if (d + sblock.fs_ipg/INOPB >= dmax) {
printf("bad blocks: cyl grp %d unusable\n", c);
exit(1);
}
goto tryagain;
}
cs->cs_ndir = 0;
acg.cg_time = utime;
acg.cg_magic = CG_MAGIC;
acg.cg_cgx = c;
acg.cg_ncyl = sblock.fs_cpg;
acg.cg_niblk = sblock.fs_ipg;
acg.cg_ndblk = dmax - cbase;
acg.cg_ndir = 0;
acg.cg_nffree = 0;
acg.cg_nbfree = 0;
acg.cg_nifree = 0;
acg.cg_rotor = 0;
i = 0;
d = cgimin(c,&sblock);
while (i < sblock.fs_ipg) {
for (j = INOPB; j > 0; j--) {
clrbit(acg.cg_iused, i);
i++;
}
acg.cg_nifree += INOPB;
d++;
}
while (i < MAXIPG) {
clrbit(acg.cg_iused, i);
i++;
}
lseek(fso, cgimin(c,&sblock)*FSIZE, 0);
if (write(fso, (char *)zino, sblock.fs_ipg * sizeof (struct dinode)) !=
sblock.fs_ipg * sizeof (struct dinode))
printf("write error %D\n", tell(fso) / BSIZE);
for (i = 0; i < MAXCPG; i++)
for (j = 0; j < NRPOS; j++)
acg.cg_b[i][j] = 0;
dmin = cgdmin(c,&sblock) - cbase;
if (c == 0) {
dmin += howmany(cssize(&sblock), BSIZE) * FRAG;
}
for (d = 0; d < dmin; d += FRAG)
clrblock(acg.cg_free, d/FRAG);
while ((d+FRAG) <= dmax - cbase) {
if (badblk(cbase+d))
clrblock(acg.cg_free, d/FRAG);
else {
setblock(acg.cg_free, d/FRAG);
acg.cg_nbfree++;
s = d * NSPF;
acg.cg_b[s/sblock.fs_spc]
[s%sblock.fs_nsect*NRPOS/sblock.fs_nsect]++;
}
d += FRAG;
}
if (d < dmax - cbase)
if (badblk(d))
for (; d < dmax - cbase; d++)
clrbit(acg.cg_free, d);
else
for (; d < dmax - cbase; d++) {
setbit(acg.cg_free, d);
acg.cg_nffree++;
}
for (; d < MAXBPG; d++)
clrbit(acg.cg_free, d);
sblock.fs_nffree += acg.cg_nffree;
sblock.fs_nbfree += acg.cg_nbfree;
cs->cs_nifree = acg.cg_nifree;
cs->cs_nbfree = acg.cg_nbfree;
wtfs(cgtod(c, &sblock), BSIZE, (char *)&acg);
}
cfile(par)
struct inode *par;
{
struct inode in;
int dbc, ibc;
char db[BSIZE];
daddr_t ib[NINDIR];
int i, f, c;
/*
* get mode, uid and gid
*/
getstr();
in.i_mode = gmode(string[0], "-bcd", IFREG, IFBLK, IFCHR, IFDIR);
in.i_mode |= gmode(string[1], "-u", 0, ISUID, 0, 0);
in.i_mode |= gmode(string[2], "-g", 0, ISGID, 0, 0);
for(i=3; i<6; i++) {
c = string[i];
if(c<'0' || c>'7') {
printf("%c/%s: bad octal mode digit\n", c, string);
error = 1;
c = 0;
}
in.i_mode |= (c-'0')<<(15-3*i);
}
in.i_uid = getnum();
in.i_gid = getnum();
/*
* general initialization prior to
* switching on format
*/
ino++;
in.i_number = ino;
for(i=0; i<BSIZE; i++)
db[i] = 0;
for(i=0; i<NINDIR; i++)
ib[i] = (daddr_t)0;
in.i_nlink = 1;
in.i_size = 0;
for(i=0; i<NDADDR; i++)
in.i_un.i_f.i_db[i] = (daddr_t)0;
for(i=0; i<NIADDR; i++)
in.i_un.i_f.i_ib[i] = (daddr_t)0;
if(par == (struct inode *)0) {
par = &in;
in.i_nlink--;
}
dbc = 0;
ibc = 0;
switch(in.i_mode&IFMT) {
case IFREG:
/*
* regular file
* contents is a file name
*/
getstr();
f = open(string, 0);
if(f < 0) {
printf("%s: cannot open\n", string);
error = 1;
break;
}
while((i=read(f, db, BSIZE)) > 0) {
in.i_size += i;
newblk(&dbc, db, &ibc, ib, i);
}
close(f);
break;
case IFBLK:
case IFCHR:
/*
* special file
* content is maj/min types
*/
i = getnum() & 0377;
f = getnum() & 0377;
in.i_un.i_d.i_rdev = makedev(i, f);
break;
case IFDIR:
/*
* directory
* put in extra links
* call recursively until
* name of "$" found
*/
par->i_nlink++;
in.i_nlink++;
entry(in.i_number, ".", &dbc, db, &ibc, ib);
entry(par->i_number, "..", &dbc, db, &ibc, ib);
in.i_size = 2*sizeof(struct direct);
for(;;) {
getstr();
if(string[0]=='$' && string[1]=='\0')
break;
if (in.i_size >= FSIZE) {
printf("can't handle direct of > %d entries\n",
NDIRECT/FRAG);
exit(1);
}
entry(ino+1, string, &dbc, db, &ibc, ib);
in.i_size += sizeof(struct direct);
cfile(&in);
}
break;
}
if(dbc != 0)
newblk(&dbc, db, &ibc, ib, roundup(dbc,FSIZE));
iput(&in, &ibc, ib);
}
gmode(c, s, m0, m1, m2, m3)
char c, *s;
{
int i;
for(i=0; s[i]; i++)
if(c == s[i])
return((&m0)[i]);
printf("%c/%s: bad mode\n", c, string);
error = 1;
return(0);
}
long
getnum()
{
int i, c;
long n;
getstr();
n = 0;
i = 0;
for(i=0; c=string[i]; i++) {
if(c<'0' || c>'9') {
printf("%s: bad number\n", string);
error = 1;
return((long)0);
}
n = n*10 + (c-'0');
}
return(n);
}
getstr()
{
int i, c;
loop:
switch(c=getch()) {
case ' ':
case '\t':
case '\n':
goto loop;
case '\0':
printf("EOF\n");
exit(1);
case ':':
while(getch() != '\n');
goto loop;
}
i = 0;
do {
string[i++] = c;
c = getch();
} while(c!=' '&&c!='\t'&&c!='\n'&&c!='\0');
string[i] = '\0';
}
rdfs(bno, size, bf)
daddr_t bno;
int size;
char *bf;
{
int n;
lseek(fsi, bno*FSIZE, 0);
n = read(fsi, bf, size);
if(n != size) {
printf("read error: %ld\n", bno);
exit(1);
}
}
wtfs(bno, size, bf)
daddr_t bno;
int size;
char *bf;
{
int n;
lseek(fso, bno*FSIZE, 0);
n = write(fso, bf, size);
if(n != size) {
printf("write error: %D\n", bno);
exit(1);
}
}
daddr_t
alloc(size)
int size;
{
int c, i, s, frag;
daddr_t d;
c = 0;
rdfs(cgtod(0,&sblock), sblock.fs_cgsize, (char *)&acg);
if (acg.cg_nbfree == 0) {
printf("first cylinder group ran out of space\n");
return (0);
}
for (d = 0; d < acg.cg_ndblk; d += FRAG)
if (isblock(acg.cg_free, d/FRAG))
goto goth;
printf("internal error: can't find block in cyl 0\n");
return (0);
goth:
clrblock(acg.cg_free, d/FRAG);
acg.cg_nbfree--;
sblock.fs_nbfree--;
fscs[0].cs_nbfree--;
s = d * NSPF;
acg.cg_b[s/sblock.fs_spc][s%sblock.fs_nsect*NRPOS/sblock.fs_nsect]--;
if (size != BSIZE) {
frag = howmany(size, FSIZE);
acg.cg_nffree += FRAG - frag;
sblock.fs_nffree += FRAG - frag;
for (i = frag; i < FRAG; i++)
setbit(acg.cg_free, d+i);
}
wtfs(cgtod(0,&sblock), sblock.fs_cgsize, (char *)&acg);
return (d);
}
entry(inum, str, adbc, db, aibc, ib)
ino_t inum;
char *str;
int *adbc, *aibc;
char *db;
daddr_t *ib;
{
struct direct *dp;
int i;
dp = (struct direct *)db;
dp += *adbc;
(*adbc)++;
dp->d_ino = inum;
for(i=0; i<DIRSIZ; i++)
dp->d_name[i] = 0;
for(i=0; i<DIRSIZ; i++)
if((dp->d_name[i] = str[i]) == 0)
break;
if(*adbc >= NDIRECT)
newblk(adbc, db, aibc, ib, BSIZE);
}
newblk(adbc, db, aibc, ib, size)
int *adbc, *aibc;
char *db;
daddr_t *ib;
int size;
{
int i;
daddr_t bno;
bno = alloc(size);
wtfs(bno, size, db);
for(i=0; i<size; i++)
db[i] = 0;
*adbc = 0;
ib[*aibc] = bno;
(*aibc)++;
if(*aibc >= NINDIR) {
printf("indirect block full\n");
error = 1;
*aibc = 0;
}
}
getch()
{
#ifndef STANDALONE
if(charp)
#endif
return(*charp++);
#ifndef STANDALONE
return(getc(fin));
#endif
}
iput(ip, aibc, ib)
struct inode *ip;
int *aibc;
daddr_t *ib;
{
struct dinode *dp;
daddr_t d;
int i, c = ip->i_number / sblock.fs_ipg;
rdfs(cgtod(c,&sblock), sblock.fs_cgsize, (char *)&acg);
acg.cg_nifree--;
setbit(acg.cg_iused, ip->i_number);
wtfs(cgtod(c,&sblock), sblock.fs_cgsize, (char *)&acg);
sblock.fs_nifree--;
fscs[0].cs_nifree--;
if(ip->i_number >= sblock.fs_ipg) {
printf("mkfs: cant handle more than one cg of inodes (yet)\n");
exit(1);
}
if(ip->i_number >= sblock.fs_ipg * sblock.fs_ncg) {
if(error == 0)
printf("ilist too small\n");
error = 1;
return;
}
d = itod(ip->i_number,&sblock);
rdfs(d, BSIZE, buf);
dp = (struct dinode *)buf;
dp += itoo(ip->i_number);
dp->di_mode = ip->i_mode;
dp->di_nlink = ip->i_nlink;
dp->di_uid = ip->i_uid;
dp->di_gid = ip->i_gid;
dp->di_size = ip->i_size;
dp->di_atime = utime;
dp->di_mtime = utime;
dp->di_ctime = utime;
switch(ip->i_mode&IFMT) {
case IFDIR:
case IFREG:
for(i=0; i<*aibc; i++) {
if(i >= NDADDR)
break;
ip->i_un.i_f.i_db[i] = ib[i];
}
if(*aibc >= NDADDR) {
ip->i_un.i_f.i_ib[0] = alloc(BSIZE);
for(i=0; i<NINDIR-NDADDR; i++) {
ib[i] = ib[i+NDADDR];
ib[i+NDADDR] = (daddr_t)0;
}
wtfs(ip->i_un.i_f.i_ib[0], (char *)ib);
}
case IFBLK:
case IFCHR:
ltol3(dp->di_addr, ip->i_un.i_f.i_db, NDADDR+NIADDR);
break;
default:
printf("bad mode %o\n", ip->i_mode);
exit(1);
}
wtfs(d, BSIZE, buf);
}
badblk(bno)
daddr_t bno;
{
return(0);
}