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