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