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
main(argc,argv)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 = ∈
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*/
gmode(c,s,m0,m1,m2,m3)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
getnum()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
getstr()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
newblk(buf,aibc,ib,size)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
alloc(size)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
ialloc(ip)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 */
rdfs(bno,size,bf)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 */
wtfs(bno,size,bf)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