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