date and time created 82/09/10 00:09:25 by mckusick
[unix-history] / usr / src / usr.sbin / mkproto / mkproto.c
/* Copyright (c) 1982 Regents of the University of California */
static char sccsid[] = "@(#)mkproto.c 4.1 (Berkeley) %G%";
/*
* Make a file system prototype.
* usage: mkproto filsys proto
*/
#include <stdio.h>
#include <sys/param.h>
#include <sys/inode.h>
#include <sys/fs.h>
#include <sys/dir.h>
union {
struct fs fs;
char fsx[SBSIZE];
} ufs;
#define sblock ufs.fs
union {
struct cg cg;
char cgx[MAXBSIZE];
} ucg;
#define acg ucg.cg
struct fs *fs;
struct csum *fscs;
int fso, fsi;
FILE *proto;
char token[BUFSIZ];
int errs;
int ino = 10;
long getnum();
char *strcpy();
main(argc, argv)
int argc;
char *argv[];
{
int i;
if (argc != 3) {
fprintf(stderr, "usage: mkproto filsys proto\n");
exit(1);
}
fso = open(argv[1], 1);
fsi = open(argv[1], 0);
if (fso < 0 || fsi < 0) {
perror(argv[1]);
exit(1);
}
fs = &sblock;
rdfs(SBLOCK, SBSIZE, (char *)fs);
fscs = (struct csum *)calloc(1, fs->fs_cssize);
for (i = 0; i < fs->fs_cssize; i += fs->fs_bsize)
rdfs(fsbtodb(fs, fs->fs_csaddr + numfrags(fs, i)),
(int)(fs->fs_cssize - i < fs->fs_bsize ?
fs->fs_cssize - i : fs->fs_bsize),
((char *)fscs) + i);
proto = fopen(argv[2], "r");
descend((struct inode *)0);
wtfs(SBLOCK, SBSIZE, (char *)fs);
for (i = 0; i < fs->fs_cssize; i += fs->fs_bsize)
wtfs(fsbtodb(&sblock, fs->fs_csaddr + numfrags(&sblock, i)),
(int)(fs->fs_cssize - i < fs->fs_bsize ?
fs->fs_cssize - i : fs->fs_bsize),
((char *)fscs) + i);
exit(errs);
}
descend(par)
struct inode *par;
{
struct inode in;
int ibc = 0;
int i, f, c;
struct dinode *dip, inos[MAXBSIZE / sizeof (struct dinode)];
daddr_t ib[MAXBSIZE / sizeof (daddr_t)];
char buf[MAXBSIZE];
getstr();
in.i_mode = gmode(token[0], "-bcd", IFREG, IFBLK, IFCHR, IFDIR);
in.i_mode |= gmode(token[1], "-u", 0, ISUID, 0, 0);
in.i_mode |= gmode(token[2], "-g", 0, ISGID, 0, 0);
for (i = 3; i < 6; i++) {
c = token[i];
if (c < '0' || c > '7') {
printf("%c/%s: bad octal mode digit\n", c, token);
errs++;
c = 0;
}
in.i_mode |= (c-'0')<<(15-3*i);
}
in.i_uid = getnum(); in.i_gid = getnum();
for (i = 0; i < fs->fs_bsize; i++)
buf[i] = 0;
for (i = 0; i < NINDIR(fs); i++)
ib[i] = (daddr_t)0;
in.i_nlink = 1;
in.i_size = 0;
for (i = 0; i < NDADDR; i++)
in.i_db[i] = (daddr_t)0;
for (i = 0; i < NIADDR; i++)
in.i_ib[i] = (daddr_t)0;
if (par != (struct inode *)0) {
ialloc(&in);
} else {
par = &in;
i = itod(fs, ROOTINO);
rdfs(fsbtodb(fs, i), fs->fs_bsize, (char *)inos);
dip = &inos[ROOTINO % INOPB(fs)];
in.i_number = ROOTINO;
in.i_nlink = dip->di_nlink;
in.i_size = dip->di_size;
in.i_db[0] = dip->di_db[0];
rdfs(fsbtodb(fs, in.i_db[0]), fs->fs_bsize, buf);
}
switch (in.i_mode&IFMT) {
case IFREG:
getstr();
f = open(token, 0);
if (f < 0) {
printf("%s: cannot open\n", token);
errs++;
break;
}
while ((i = read(f, buf, (int)fs->fs_bsize)) > 0) {
in.i_size += i;
newblk(buf, &ibc, ib, (int)blksize(fs, &in, ibc));
}
close(f);
break;
case IFBLK:
case IFCHR:
/*
* special file
* content is maj/min types
*/
i = getnum() & 0377;
f = getnum() & 0377;
in.i_dev = (i << 8) | f;
break;
case IFDIR:
/*
* directory
* put in extra links
* call recursively until
* name of "$" found
*/
if (in.i_number != ROOTINO) {
par->i_nlink++;
in.i_nlink++;
entry(&in, in.i_number, ".", buf);
entry(&in, par->i_number, "..", buf);
}
for (;;) {
getstr();
if (token[0]=='$' && token[1]=='\0')
break;
entry(&in, (ino_t)(ino+1), token, buf);
descend(&in);
}
if (in.i_number != ROOTINO)
newblk(buf, &ibc, ib, (int)blksize(fs, &in, 0));
else
wtfs(fsbtodb(fs, in.i_db[0]), (int)fs->fs_bsize, buf);
break;
}
iput(&in, &ibc, ib);
}
/*ARGSUSED*/
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, token);
errs++;
return(0);
}
long
getnum()
{
int i, c;
long n;
getstr();
n = 0;
i = 0;
for (i = 0; c=token[i]; i++) {
if (c<'0' || c>'9') {
printf("%s: bad number\n", token);
errs++;
return((long)0);
}
n = n*10 + (c-'0');
}
return(n);
}
getstr()
{
int i, c;
loop:
switch (c = getc(proto)) {
case ' ':
case '\t':
case '\n':
goto loop;
case EOF:
printf("Unexpected EOF\n");
exit(1);
case ':':
while (getc(proto) != '\n')
;
goto loop;
}
i = 0;
do {
token[i++] = c;
c = getc(proto);
} while (c != ' ' && c != '\t' && c != '\n' && c != '\0');
token[i] = 0;
}
entry(ip, inum, str, buf)
struct inode *ip;
ino_t inum;
char *str;
char *buf;
{
register struct direct *dp, *odp;
int oldsize, newsize, freespace;
odp = dp = (struct direct *)buf;
while ((int)dp - (int)buf < ip->i_size) {
odp = dp;
dp = (struct direct *)((int)dp + dp->d_reclen);
}
if (odp != dp)
oldsize = DIRSIZ(odp);
else
oldsize = 0;
freespace = odp->d_reclen - oldsize;
dp = (struct direct *)((int)odp + oldsize);
dp->d_ino = inum;
dp->d_namlen = strlen(str);
newsize = DIRSIZ(dp);
if (freespace >= newsize) {
odp->d_reclen = oldsize;
dp->d_reclen = freespace;
} else {
dp = (struct direct *)((int)odp + odp->d_reclen);
if ((int)dp - (int)buf >= fs->fs_bsize) {
printf("directory too large\n");
exit(1);
}
dp->d_ino = inum;
dp->d_namlen = strlen(str);
dp->d_reclen = DIRBLKSIZ;
}
strcpy(dp->d_name, str);
ip->i_size = (int)dp - (int)buf + newsize;
}
newblk(buf, aibc, ib, size)
int *aibc;
char *buf;
daddr_t *ib;
int size;
{
int i;
daddr_t bno;
bno = alloc(size);
wtfs(fsbtodb(fs, bno), (int)fs->fs_bsize, buf);
for (i = 0; i < fs->fs_bsize; i++)
buf[i] = 0;
ib[(*aibc)++] = bno;
if (*aibc >= NINDIR(fs)) {
printf("indirect block full\n");
errs++;
*aibc = 0;
}
}
iput(ip, aibc, ib)
struct inode *ip;
int *aibc;
daddr_t *ib;
{
daddr_t d;
int i;
struct dinode buf[MAXBSIZE / sizeof (struct dinode)];
ip->i_atime = ip->i_mtime = ip->i_ctime = time((long *)0);
switch (ip->i_mode&IFMT) {
case IFDIR:
case IFREG:
for (i = 0; i < *aibc; i++) {
if (i >= NDADDR)
break;
ip->i_db[i] = ib[i];
}
if (*aibc > NDADDR) {
ip->i_ib[0] = alloc((int)fs->fs_bsize);
for (i = 0; i < NINDIR(fs) - NDADDR; i++) {
ib[i] = ib[i+NDADDR];
ib[i+NDADDR] = (daddr_t)0;
}
wtfs(fsbtodb(fs, ip->i_ib[0]),
(int)fs->fs_bsize, (char *)ib);
}
break;
case IFBLK:
case IFCHR:
break;
default:
printf("bad mode %o\n", ip->i_mode);
exit(1);
}
d = fsbtodb(fs, itod(fs, ip->i_number));
rdfs(d, (int)fs->fs_bsize, (char *)buf);
buf[itoo(fs, ip->i_number)].di_ic = ip->i_ic;
wtfs(d, (int)fs->fs_bsize, (char *)buf);
}
daddr_t
alloc(size)
int size;
{
int i, frag;
daddr_t d;
static int cg = 0;
again:
rdfs(fsbtodb(&sblock, cgtod(&sblock, cg)), (int)sblock.fs_cgsize,
(char *)&acg);
if (acg.cg_magic != CG_MAGIC) {
printf("cg %d: bad magic number\n", cg);
return (0);
}
if (acg.cg_cs.cs_nbfree == 0) {
cg++;
if (cg >= fs->fs_ncg) {
printf("ran out of space\n");
return (0);
}
goto again;
}
for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
if (isblock(&sblock, (u_char *)acg.cg_free, d / sblock.fs_frag))
goto goth;
printf("internal error: can't find block in cyl %d\n", cg);
return (0);
goth:
clrblock(&sblock, (u_char *)acg.cg_free, d / sblock.fs_frag);
acg.cg_cs.cs_nbfree--;
sblock.fs_cstotal.cs_nbfree--;
fscs[cg].cs_nbfree--;
acg.cg_btot[cbtocylno(&sblock, d)]--;
acg.cg_b[cbtocylno(&sblock, d)][cbtorpos(&sblock, d)]--;
if (size != sblock.fs_bsize) {
frag = howmany(size, sblock.fs_fsize);
fscs[cg].cs_nffree += sblock.fs_frag - frag;
sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
acg.cg_frsum[sblock.fs_frag - frag]++;
for (i = frag; i < sblock.fs_frag; i++)
setbit(acg.cg_free, d + i);
}
wtfs(fsbtodb(&sblock, cgtod(&sblock, cg)), (int)sblock.fs_cgsize,
(char *)&acg);
return (acg.cg_cgx * fs->fs_fpg + d);
}
/*
* Allocate an inode on the disk
*/
ialloc(ip)
register struct inode *ip;
{
struct dinode buf[MAXBSIZE / sizeof (struct dinode)];
daddr_t d;
int c;
ip->i_number = ++ino;
c = itog(&sblock, ip->i_number);
rdfs(fsbtodb(&sblock, cgtod(&sblock, c)), (int)sblock.fs_cgsize,
(char *)&acg);
if (acg.cg_magic != CG_MAGIC) {
printf("cg %d: bad magic number\n", c);
exit(1);
}
if (ip->i_mode & IFDIR) {
acg.cg_cs.cs_ndir++;
sblock.fs_cstotal.cs_ndir++;
fscs[c].cs_ndir++;
}
acg.cg_cs.cs_nifree--;
setbit(acg.cg_iused, ip->i_number);
wtfs(fsbtodb(&sblock, cgtod(&sblock, c)), (int)sblock.fs_cgsize,
(char *)&acg);
sblock.fs_cstotal.cs_nifree--;
fscs[c].cs_nifree--;
if(ip->i_number >= sblock.fs_ipg * sblock.fs_ncg) {
printf("fsinit: inode value out of range (%d).\n",
ip->i_number);
exit(1);
}
return (ip->i_number);
}
/*
* read a block from the file system
*/
rdfs(bno, size, bf)
int bno, size;
char *bf;
{
int n;
if (lseek(fsi, bno * DEV_BSIZE, 0) < 0) {
printf("seek error: %ld\n", bno);
perror("rdfs");
exit(1);
}
n = read(fsi, bf, size);
if(n != size) {
printf("read error: %ld\n", bno);
perror("rdfs");
exit(1);
}
}
/*
* write a block to the file system
*/
wtfs(bno, size, bf)
int bno, size;
char *bf;
{
int n;
lseek(fso, bno * DEV_BSIZE, 0);
if (lseek(fso, bno * DEV_BSIZE, 0) < 0) {
printf("seek error: %ld\n", bno);
perror("wtfs");
exit(1);
}
n = write(fso, bf, size);
if(n != size) {
printf("write error: %D\n", bno);
perror("wtfs");
exit(1);
}
}
/*
* check if a block is available
*/
isblock(fs, cp, h)
struct fs *fs;
unsigned char *cp;
int h;
{
unsigned char mask;
switch (fs->fs_frag) {
case 8:
return (cp[h] == 0xff);
case 4:
mask = 0x0f << ((h & 0x1) << 2);
return ((cp[h >> 1] & mask) == mask);
case 2:
mask = 0x03 << ((h & 0x3) << 1);
return ((cp[h >> 2] & mask) == mask);
case 1:
mask = 0x01 << (h & 0x7);
return ((cp[h >> 3] & mask) == mask);
default:
fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
return (0);
}
/*NOTREACHED*/
}
/*
* take a block out of the map
*/
clrblock(fs, cp, h)
struct fs *fs;
unsigned char *cp;
int h;
{
switch ((fs)->fs_frag) {
case 8:
cp[h] = 0;
return;
case 4:
cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
return;
case 2:
cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
return;
case 1:
cp[h >> 3] &= ~(0x01 << (h & 0x7));
return;
default:
fprintf(stderr, "clrblock bad fs_frag %d\n", fs->fs_frag);
return;
}
}