+/*
+ * Make a file system prototype.
+ * usage: mkfs filsys proto/size [ m n ]
+ */
+#define NIPB (BSIZE/sizeof(struct dinode))
+#define NINDIR (BSIZE/sizeof(daddr_t))
+#define NDIRECT (BSIZE/sizeof(struct direct))
+#define LADDR 10
+#define MAXFN 500
+#define itoo(x) (int)((x+15)&07)
+#ifndef STANDALONE
+#include <stdio.h>
+#include <a.out.h>
+#endif
+#include <sys/param.h>
+#include <sys/ino.h>
+#include <sys/inode.h>
+#include <sys/filsys.h>
+#include <sys/fblk.h>
+#include <sys/dir.h>
+time_t utime;
+#ifndef STANDALONE
+FILE *fin;
+#else
+int fin;
+#endif
+int fsi;
+int fso;
+char *charp;
+char buf[BSIZE];
+union {
+ struct fblk fb;
+ char pad1[BSIZE];
+} fbuf;
+#ifndef STANDALONE
+struct exec head;
+#endif
+char string[50];
+union {
+ struct filsys fs;
+ char pad2[BSIZE];
+} filsys;
+char *fsys;
+char *proto;
+int f_n = MAXFN;
+int f_m = 3;
+int error;
+ino_t ino;
+long getnum();
+daddr_t alloc();
+
+main(argc, argv)
+char *argv[];
+{
+ int f, c;
+ long n;
+
+#ifndef STANDALONE
+ time(&utime);
+ if(argc < 3) {
+ printf("usage: mkfs filsys proto/size [ m n ]\n");
+ exit(1);
+ }
+ fsys = argv[1];
+ proto = argv[2];
+#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
+ if(fin == NULL) {
+ 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');
+ }
+ filsys.s_fsize = n;
+ n = n/25;
+ if(n <= 0)
+ n = 1;
+ if(n > 65500/NIPB)
+ n = 65500/NIPB;
+ filsys.s_isize = n + 2;
+ printf("isize = %D\n", n*NIPB);
+ charp = "d--777 0 0 $ ";
+ goto f3;
+ }
+
+#ifndef STANDALONE
+ /*
+ * get name of boot load program
+ * and read onto block 0
+ */
+
+ getstr();
+ f = open(string, 0);
+ if(f < 0) {
+ printf("%s: cannot open init\n", string);
+ goto f2;
+ }
+ read(f, (char *)&head, sizeof head);
+ if(head.a_magic != A_MAGIC1) {
+ printf("%s: bad format\n", string);
+ goto f1;
+ }
+ c = head.a_text + head.a_data;
+ if(c > BSIZE) {
+ printf("%s: too big\n", string);
+ goto f1;
+ }
+ read(f, buf, c);
+ wtfs((long)0, buf);
+
+f1:
+ close(f);
+
+ /*
+ * get total disk size
+ * and inode block size
+ */
+
+f2:
+ filsys.s_fsize = getnum();
+ n = getnum();
+ n /= NIPB;
+ filsys.s_isize = n + 3;
+
+#endif
+f3:
+ if(argc >= 5) {
+ f_m = atoi(argv[3]);
+ f_n = atoi(argv[4]);
+ if(f_n <= 0 || f_n >= MAXFN)
+ f_n = MAXFN;
+ if(f_m <= 0 || f_m > f_n)
+ f_m = 3;
+ }
+ filsys.s_m = f_m;
+ filsys.s_n = f_n;
+ printf("m/n = %d %d\n", f_m, f_n);
+ if(filsys.s_isize >= filsys.s_fsize) {
+ printf("%ld/%ld: bad ratio\n", filsys.s_fsize, filsys.s_isize-2);
+ exit(1);
+ }
+ filsys.s_tfree = 0;
+ filsys.s_tinode = 0;
+ for(c=0; c<BSIZE; c++)
+ buf[c] = 0;
+ for(n=2; n!=filsys.s_isize; n++) {
+ wtfs(n, buf);
+ filsys.s_tinode += NIPB;
+ }
+ ino = 0;
+
+ bflist();
+
+ cfile((struct inode *)0);
+
+ filsys.s_time = utime;
+ wtfs((long)1, (char *)&filsys);
+ exit(error);
+}
+
+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<NADDR; i++)
+ in.i_un.i_addr[i] = (daddr_t)0;
+ if(par == (struct inode *)0) {
+ par = ∈
+ 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);
+ }
+ close(f);
+ break;
+
+ case IFBLK:
+ case IFCHR:
+ /*
+ * special file
+ * content is maj/min types
+ */
+
+ i = getnum() & 0377;
+ f = getnum() & 0377;
+ in.i_un.i_addr[0] = (i<<8) | 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;
+ 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);
+ 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, bf)
+daddr_t bno;
+char *bf;
+{
+ int n;
+
+ lseek(fsi, bno*BSIZE, 0);
+ n = read(fsi, bf, BSIZE);
+ if(n != BSIZE) {
+ printf("read error: %ld\n", bno);
+ exit(1);
+ }
+}
+
+wtfs(bno, bf)
+daddr_t bno;
+char *bf;
+{
+ int n;
+
+ lseek(fso, bno*BSIZE, 0);
+ n = write(fso, bf, BSIZE);
+ if(n != BSIZE) {
+ printf("write error: %D\n", bno);
+ exit(1);
+ }
+}
+
+daddr_t
+alloc()
+{
+ int i;
+ daddr_t bno;
+
+ filsys.s_tfree--;
+ bno = filsys.s_free[--filsys.s_nfree];
+ if(bno == 0) {
+ printf("out of free space\n");
+ exit(1);
+ }
+ if(filsys.s_nfree <= 0) {
+ rdfs(bno, (char *)&fbuf);
+ filsys.s_nfree = fbuf.df_nfree;
+ for(i=0; i<NICFREE; i++)
+ filsys.s_free[i] = fbuf.df_free[i];
+ }
+ return(bno);
+}
+
+bfree(bno)
+daddr_t bno;
+{
+ int i;
+
+ filsys.s_tfree++;
+ if(filsys.s_nfree >= NICFREE) {
+ fbuf.df_nfree = filsys.s_nfree;
+ for(i=0; i<NICFREE; i++)
+ fbuf.df_free[i] = filsys.s_free[i];
+ wtfs(bno, (char *)&fbuf);
+ filsys.s_nfree = 0;
+ }
+ filsys.s_free[filsys.s_nfree++] = bno;
+}
+
+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);
+}
+
+newblk(adbc, db, aibc, ib)
+int *adbc, *aibc;
+char *db;
+daddr_t *ib;
+{
+ int i;
+ daddr_t bno;
+
+ bno = alloc();
+ wtfs(bno, db);
+ for(i=0; i<BSIZE; 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
+}
+
+bflist()
+{
+ struct inode in;
+ daddr_t ib[NINDIR];
+ int ibc;
+ char flg[MAXFN];
+ int adr[MAXFN];
+ int i, j;
+ daddr_t f, d;
+
+ for(i=0; i<f_n; i++)
+ flg[i] = 0;
+ i = 0;
+ for(j=0; j<f_n; j++) {
+ while(flg[i])
+ i = (i+1)%f_n;
+ adr[j] = i+1;
+ flg[i]++;
+ i = (i+f_m)%f_n;
+ }
+
+ ino++;
+ in.i_number = ino;
+ in.i_mode = IFREG;
+ in.i_uid = 0;
+ in.i_gid = 0;
+ in.i_nlink = 0;
+ in.i_size = 0;
+ for(i=0; i<NADDR; i++)
+ in.i_un.i_addr[i] = (daddr_t)0;
+
+ for(i=0; i<NINDIR; i++)
+ ib[i] = (daddr_t)0;
+ ibc = 0;
+ bfree((daddr_t)0);
+ d = filsys.s_fsize-1;
+ while(d%f_n)
+ d++;
+ for(; d > 0; d -= f_n)
+ for(i=0; i<f_n; i++) {
+ f = d - adr[i];
+ if(f < filsys.s_fsize && f >= filsys.s_isize)
+ if(badblk(f)) {
+ if(ibc >= NINDIR) {
+ printf("too many bad blocks\n");
+ error = 1;
+ ibc = 0;
+ }
+ ib[ibc] = f;
+ ibc++;
+ } else
+ bfree(f);
+ }
+ iput(&in, &ibc, ib);
+}
+
+iput(ip, aibc, ib)
+struct inode *ip;
+int *aibc;
+daddr_t *ib;
+{
+ struct dinode *dp;
+ daddr_t d;
+ int i;
+
+ filsys.s_tinode--;
+ d = itod(ip->i_number);
+ if(d >= filsys.s_isize) {
+ if(error == 0)
+ printf("ilist too small\n");
+ error = 1;
+ return;
+ }
+ rdfs(d, 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 >= LADDR)
+ break;
+ ip->i_un.i_addr[i] = ib[i];
+ }
+ if(*aibc >= LADDR) {
+ ip->i_un.i_addr[LADDR] = alloc();
+ for(i=0; i<NINDIR-LADDR; i++) {
+ ib[i] = ib[i+LADDR];
+ ib[i+LADDR] = (daddr_t)0;
+ }
+ wtfs(ip->i_un.i_addr[LADDR], (char *)ib);
+ }
+
+ case IFBLK:
+ case IFCHR:
+ ltol3(dp->di_addr, ip->i_un.i_addr, NADDR);
+ break;
+
+ default:
+ printf("bad mode %o\n", ip->i_mode);
+ exit(1);
+ }
+ wtfs(d, buf);
+}
+
+badblk(bno)
+daddr_t bno;
+{
+
+ return(0);
+}