xref: /original-bsd/usr.sbin/mkproto/mkproto.c (revision 2bb802fc)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)mkproto.c	5.4 (Berkeley) 05/31/88";
15 #endif not lint
16 
17 /*
18  * Make a file system prototype.
19  * usage: mkproto filsys proto
20  */
21 #include <stdio.h>
22 #include <sys/param.h>
23 #include <sys/inode.h>
24 #include <sys/fs.h>
25 #include <sys/dir.h>
26 
27 union {
28 	struct	fs fs;
29 	char	fsx[SBSIZE];
30 } ufs;
31 #define sblock	ufs.fs
32 union {
33 	struct	cg cg;
34 	char	cgx[MAXBSIZE];
35 } ucg;
36 #define	acg	ucg.cg
37 struct	fs *fs;
38 struct	csum *fscs;
39 int	fso, fsi;
40 FILE	*proto;
41 char	token[BUFSIZ];
42 int	errs;
43 long	dev_bsize = 1;
44 int	ino = 10;
45 long	getnum();
46 char	*strcpy();
47 
48 main(argc, argv)
49 	int argc;
50 	char *argv[];
51 {
52 	int i;
53 	char *calloc();
54 
55 	if (argc != 3) {
56 		fprintf(stderr, "usage: mkproto filsys proto\n");
57 		exit(1);
58 	}
59 	fso = open(argv[1], 1);
60 	fsi = open(argv[1], 0);
61 	if (fso < 0 || fsi < 0) {
62 		perror(argv[1]);
63 		exit(1);
64 	}
65 	fs = &sblock;
66 	rdfs(SBOFF, SBSIZE, (char *)fs);
67 	dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
68 	fscs = (struct csum *)calloc(1, (u_int)fs->fs_cssize);
69 	for (i = 0; i < fs->fs_cssize; i += fs->fs_bsize)
70 		rdfs(fsbtodb(fs, fs->fs_csaddr + numfrags(fs, i)),
71 			(int)(fs->fs_cssize - i < fs->fs_bsize ?
72 			    fs->fs_cssize - i : fs->fs_bsize),
73 			((char *)fscs) + i);
74 	proto = fopen(argv[2], "r");
75 	descend((struct inode *)0);
76 	wtfs(SBOFF / dev_bsize, SBSIZE, (char *)fs);
77 	for (i = 0; i < fs->fs_cssize; i += fs->fs_bsize)
78 		wtfs(fsbtodb(&sblock, fs->fs_csaddr + numfrags(&sblock, i)),
79 			(int)(fs->fs_cssize - i < fs->fs_bsize ?
80 			    fs->fs_cssize - i : fs->fs_bsize),
81 			((char *)fscs) + i);
82 	exit(errs);
83 }
84 
85 descend(par)
86 	struct inode *par;
87 {
88 	struct inode in;
89 	int ibc = 0;
90 	int i, f, c;
91 	struct dinode *dip, inos[MAXBSIZE / sizeof (struct dinode)];
92 	daddr_t ib[MAXBSIZE / sizeof (daddr_t)];
93 	char buf[MAXBSIZE];
94 
95 	getstr();
96 	in.i_mode = gmode(token[0], "-bcd", IFREG, IFBLK, IFCHR, IFDIR);
97 	in.i_mode |= gmode(token[1], "-u", 0, ISUID, 0, 0);
98 	in.i_mode |= gmode(token[2], "-g", 0, ISGID, 0, 0);
99 	for (i = 3; i < 6; i++) {
100 		c = token[i];
101 		if (c < '0' || c > '7') {
102 			printf("%c/%s: bad octal mode digit\n", c, token);
103 			errs++;
104 			c = 0;
105 		}
106 		in.i_mode |= (c-'0')<<(15-3*i);
107 	}
108 	in.i_uid = getnum(); in.i_gid = getnum();
109 	for (i = 0; i < fs->fs_bsize; i++)
110 		buf[i] = 0;
111 	for (i = 0; i < NINDIR(fs); i++)
112 		ib[i] = (daddr_t)0;
113 	in.i_nlink = 1;
114 	in.i_size = 0;
115 	for (i = 0; i < NDADDR; i++)
116 		in.i_db[i] = (daddr_t)0;
117 	for (i = 0; i < NIADDR; i++)
118 		in.i_ib[i] = (daddr_t)0;
119 	if (par != (struct inode *)0) {
120 		ialloc(&in);
121 	} else {
122 		par = &in;
123 		i = itod(fs, ROOTINO);
124 		rdfs(fsbtodb(fs, i), fs->fs_bsize, (char *)inos);
125 		dip = &inos[ROOTINO % INOPB(fs)];
126 		in.i_number = ROOTINO;
127 		in.i_nlink = dip->di_nlink;
128 		in.i_size = dip->di_size;
129 		in.i_db[0] = dip->di_db[0];
130 		rdfs(fsbtodb(fs, in.i_db[0]), fs->fs_bsize, buf);
131 	}
132 
133 	switch (in.i_mode&IFMT) {
134 
135 	case IFREG:
136 		getstr();
137 		f = open(token, 0);
138 		if (f < 0) {
139 			printf("%s: cannot open\n", token);
140 			errs++;
141 			break;
142 		}
143 		while ((i = read(f, buf, (int)fs->fs_bsize)) > 0) {
144 			in.i_size += i;
145 			newblk(buf, &ibc, ib, (int)blksize(fs, &in, ibc));
146 		}
147 		close(f);
148 		break;
149 
150 	case IFBLK:
151 	case IFCHR:
152 		/*
153 		 * special file
154 		 * content is maj/min types
155 		 */
156 
157 		i = getnum() & 0377;
158 		f = getnum() & 0377;
159 		in.i_rdev = (i << 8) | f;
160 		break;
161 
162 	case IFDIR:
163 		/*
164 		 * directory
165 		 * put in extra links
166 		 * call recursively until
167 		 * name of "$" found
168 		 */
169 
170 		if (in.i_number != ROOTINO) {
171 			par->i_nlink++;
172 			in.i_nlink++;
173 			entry(&in, in.i_number, ".", buf);
174 			entry(&in, par->i_number, "..", buf);
175 		}
176 		for (;;) {
177 			getstr();
178 			if (token[0]=='$' && token[1]=='\0')
179 				break;
180 			entry(&in, (ino_t)(ino+1), token, buf);
181 			descend(&in);
182 		}
183 		if (in.i_number != ROOTINO)
184 			newblk(buf, &ibc, ib, (int)blksize(fs, &in, 0));
185 		else
186 			wtfs(fsbtodb(fs, in.i_db[0]), (int)fs->fs_bsize, buf);
187 		break;
188 	}
189 	iput(&in, &ibc, ib);
190 }
191 
192 /*ARGSUSED*/
193 gmode(c, s, m0, m1, m2, m3)
194 	char c, *s;
195 {
196 	int i;
197 
198 	for (i = 0; s[i]; i++)
199 		if (c == s[i])
200 			return((&m0)[i]);
201 	printf("%c/%s: bad mode\n", c, token);
202 	errs++;
203 	return(0);
204 }
205 
206 long
207 getnum()
208 {
209 	int i, c;
210 	long n;
211 
212 	getstr();
213 	n = 0;
214 	i = 0;
215 	for (i = 0; c=token[i]; i++) {
216 		if (c<'0' || c>'9') {
217 			printf("%s: bad number\n", token);
218 			errs++;
219 			return((long)0);
220 		}
221 		n = n*10 + (c-'0');
222 	}
223 	return(n);
224 }
225 
226 getstr()
227 {
228 	int i, c;
229 
230 loop:
231 	switch (c = getc(proto)) {
232 
233 	case ' ':
234 	case '\t':
235 	case '\n':
236 		goto loop;
237 
238 	case EOF:
239 		printf("Unexpected EOF\n");
240 		exit(1);
241 
242 	case ':':
243 		while (getc(proto) != '\n')
244 			;
245 		goto loop;
246 
247 	}
248 	i = 0;
249 	do {
250 		token[i++] = c;
251 		c = getc(proto);
252 	} while (c != ' ' && c != '\t' && c != '\n' && c != '\0');
253 	token[i] = 0;
254 }
255 
256 entry(ip, inum, str, buf)
257 	struct inode *ip;
258 	ino_t inum;
259 	char *str;
260 	char *buf;
261 {
262 	register struct direct *dp, *odp;
263 	int oldsize, newsize, spacefree;
264 
265 	odp = dp = (struct direct *)buf;
266 	while ((int)dp - (int)buf < ip->i_size) {
267 		odp = dp;
268 		dp = (struct direct *)((int)dp + dp->d_reclen);
269 	}
270 	if (odp != dp)
271 		oldsize = DIRSIZ(odp);
272 	else
273 		oldsize = 0;
274 	spacefree = odp->d_reclen - oldsize;
275 	dp = (struct direct *)((int)odp + oldsize);
276 	dp->d_ino = inum;
277 	dp->d_namlen = strlen(str);
278 	newsize = DIRSIZ(dp);
279 	if (spacefree >= newsize) {
280 		odp->d_reclen = oldsize;
281 		dp->d_reclen = spacefree;
282 	} else {
283 		dp = (struct direct *)((int)odp + odp->d_reclen);
284 		if ((int)dp - (int)buf >= fs->fs_bsize) {
285 			printf("directory too large\n");
286 			exit(1);
287 		}
288 		dp->d_ino = inum;
289 		dp->d_namlen = strlen(str);
290 		dp->d_reclen = DIRBLKSIZ;
291 	}
292 	strcpy(dp->d_name, str);
293 	ip->i_size = (int)dp - (int)buf + newsize;
294 }
295 
296 newblk(buf, aibc, ib, size)
297 	int *aibc;
298 	char *buf;
299 	daddr_t *ib;
300 	int size;
301 {
302 	int i;
303 	daddr_t bno, alloc();
304 
305 	bno = alloc(size);
306 	wtfs(fsbtodb(fs, bno), (int)fs->fs_bsize, buf);
307 	for (i = 0; i < fs->fs_bsize; i++)
308 		buf[i] = 0;
309 	ib[(*aibc)++] = bno;
310 	if (*aibc >= NINDIR(fs)) {
311 		printf("indirect block full\n");
312 		errs++;
313 		*aibc = 0;
314 	}
315 }
316 
317 iput(ip, aibc, ib)
318 	struct inode *ip;
319 	int *aibc;
320 	daddr_t *ib;
321 {
322 	daddr_t d, alloc();
323 	int i;
324 	struct dinode buf[MAXBSIZE / sizeof (struct dinode)];
325 	time_t time();
326 
327 	ip->i_atime = ip->i_mtime = ip->i_ctime = time((time_t *)NULL);
328 	switch (ip->i_mode&IFMT) {
329 
330 	case IFDIR:
331 	case IFREG:
332 		for (i = 0; i < *aibc; i++) {
333 			if (i >= NDADDR)
334 				break;
335 			ip->i_db[i] = ib[i];
336 		}
337 		if (*aibc > NDADDR) {
338 			ip->i_ib[0] = alloc((int)fs->fs_bsize);
339 			for (i = 0; i < NINDIR(fs) - NDADDR; i++) {
340 				ib[i] = ib[i+NDADDR];
341 				ib[i+NDADDR] = (daddr_t)0;
342 			}
343 			wtfs(fsbtodb(fs, ip->i_ib[0]),
344 			    (int)fs->fs_bsize, (char *)ib);
345 		}
346 		break;
347 
348 	case IFBLK:
349 	case IFCHR:
350 		break;
351 
352 	default:
353 		printf("bad mode %o\n", ip->i_mode);
354 		exit(1);
355 	}
356 	d = fsbtodb(fs, itod(fs, ip->i_number));
357 	rdfs(d, (int)fs->fs_bsize, (char *)buf);
358 	buf[itoo(fs, ip->i_number)].di_ic = ip->i_ic;
359 	wtfs(d, (int)fs->fs_bsize, (char *)buf);
360 }
361 
362 daddr_t
363 alloc(size)
364 	int size;
365 {
366 	int i, frag;
367 	daddr_t d;
368 	static int cg = 0;
369 
370 again:
371 	rdfs(fsbtodb(&sblock, cgtod(&sblock, cg)), (int)sblock.fs_cgsize,
372 	    (char *)&acg);
373 	if (!cg_chkmagic(&acg)) {
374 		printf("cg %d: bad magic number\n", cg);
375 		return (0);
376 	}
377 	if (acg.cg_cs.cs_nbfree == 0) {
378 		cg++;
379 		if (cg >= fs->fs_ncg) {
380 			printf("ran out of space\n");
381 			return (0);
382 		}
383 		goto again;
384 	}
385 	for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
386 		if (isblock(&sblock, (u_char *)cg_blksfree(&acg),
387 		    d / sblock.fs_frag))
388 			goto goth;
389 	printf("internal error: can't find block in cyl %d\n", cg);
390 	return (0);
391 goth:
392 	clrblock(&sblock, (u_char *)cg_blksfree(&acg), d / sblock.fs_frag);
393 	acg.cg_cs.cs_nbfree--;
394 	sblock.fs_cstotal.cs_nbfree--;
395 	fscs[cg].cs_nbfree--;
396 	cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
397 	cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--;
398 	if (size != sblock.fs_bsize) {
399 		frag = howmany(size, sblock.fs_fsize);
400 		fscs[cg].cs_nffree += sblock.fs_frag - frag;
401 		sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
402 		acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
403 		acg.cg_frsum[sblock.fs_frag - frag]++;
404 		for (i = frag; i < sblock.fs_frag; i++)
405 			setbit(cg_blksfree(&acg), d + i);
406 	}
407 	wtfs(fsbtodb(&sblock, cgtod(&sblock, cg)), (int)sblock.fs_cgsize,
408 	    (char *)&acg);
409 	return (acg.cg_cgx * fs->fs_fpg + d);
410 }
411 
412 /*
413  * Allocate an inode on the disk
414  */
415 ialloc(ip)
416 	register struct inode *ip;
417 {
418 	int c;
419 
420 	ip->i_number = ++ino;
421 	c = itog(&sblock, ip->i_number);
422 	rdfs(fsbtodb(&sblock, cgtod(&sblock, c)), (int)sblock.fs_cgsize,
423 	    (char *)&acg);
424 	if (!cg_chkmagic(&acg)) {
425 		printf("cg %d: bad magic number\n", c);
426 		exit(1);
427 	}
428 	if (ip->i_mode & IFDIR) {
429 		acg.cg_cs.cs_ndir++;
430 		sblock.fs_cstotal.cs_ndir++;
431 		fscs[c].cs_ndir++;
432 	}
433 	acg.cg_cs.cs_nifree--;
434 	setbit(cg_inosused(&acg), ip->i_number);
435 	wtfs(fsbtodb(&sblock, cgtod(&sblock, c)), (int)sblock.fs_cgsize,
436 	    (char *)&acg);
437 	sblock.fs_cstotal.cs_nifree--;
438 	fscs[c].cs_nifree--;
439 	if(ip->i_number >= sblock.fs_ipg * sblock.fs_ncg) {
440 		printf("fsinit: inode value out of range (%lu).\n",
441 		    ip->i_number);
442 		exit(1);
443 	}
444 	/* return (ip->i_number); */
445 }
446 
447 /*
448  * read a block from the file system
449  */
450 rdfs(bno, size, bf)
451 	int bno, size;
452 	char *bf;
453 {
454 	int n;
455 	off_t lseek();
456 
457 	if (lseek(fsi, bno * dev_bsize, 0) < 0) {
458 		printf("seek error: %d\n", bno);
459 		perror("rdfs");
460 		exit(1);
461 	}
462 	n = read(fsi, bf, size);
463 	if(n != size) {
464 		printf("read error: %d\n", bno);
465 		perror("rdfs");
466 		exit(1);
467 	}
468 }
469 
470 /*
471  * write a block to the file system
472  */
473 wtfs(bno, size, bf)
474 	int bno, size;
475 	char *bf;
476 {
477 	int n;
478 	off_t lseek();
479 
480 	if (lseek(fso, bno * dev_bsize, 0) < 0) {
481 		printf("seek error: %d\n", bno);
482 		perror("wtfs");
483 		exit(1);
484 	}
485 	n = write(fso, bf, size);
486 	if(n != size) {
487 		printf("write error: %d\n", bno);
488 		perror("wtfs");
489 		exit(1);
490 	}
491 }
492 /*
493  * check if a block is available
494  */
495 isblock(fs, cp, h)
496 	struct fs *fs;
497 	unsigned char *cp;
498 	int h;
499 {
500 	unsigned char mask;
501 
502 	switch (fs->fs_frag) {
503 	case 8:
504 		return (cp[h] == 0xff);
505 	case 4:
506 		mask = 0x0f << ((h & 0x1) << 2);
507 		return ((cp[h >> 1] & mask) == mask);
508 	case 2:
509 		mask = 0x03 << ((h & 0x3) << 1);
510 		return ((cp[h >> 2] & mask) == mask);
511 	case 1:
512 		mask = 0x01 << (h & 0x7);
513 		return ((cp[h >> 3] & mask) == mask);
514 	default:
515 		fprintf(stderr, "isblock bad fs_frag %ld\n", fs->fs_frag);
516 		return (0);
517 	}
518 	/*NOTREACHED*/
519 }
520 
521 /*
522  * take a block out of the map
523  */
524 clrblock(fs, cp, h)
525 	struct fs *fs;
526 	unsigned char *cp;
527 	int h;
528 {
529 	switch ((fs)->fs_frag) {
530 	case 8:
531 		cp[h] = 0;
532 		return;
533 	case 4:
534 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
535 		return;
536 	case 2:
537 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
538 		return;
539 	case 1:
540 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
541 		return;
542 	default:
543 		fprintf(stderr, "clrblock bad fs_frag %ld\n", fs->fs_frag);
544 		return;
545 	}
546 }
547 
548