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