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