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