Commit | Line | Data |
---|---|---|
f5262822 | 1 | static char sccsid[] = "@(#)main.c 2.14 (Berkeley) %G%"; |
07670f7d | 2 | |
6e884967 KM |
3 | #include <stdio.h> |
4 | #include <ctype.h> | |
4d308541 KM |
5 | #include <sys/param.h> |
6 | #include <sys/fs.h> | |
7 | #include <sys/inode.h> | |
6c6be8f1 | 8 | #include <dir.h> |
4d308541 | 9 | #include <sys/stat.h> |
6e884967 KM |
10 | #include <fstab.h> |
11 | ||
12 | typedef int (*SIG_TYP)(); | |
13 | ||
c312eebd KM |
14 | #define MAXNINDIR (MAXBSIZE / sizeof (daddr_t)) |
15 | #define MAXINOPB (MAXBSIZE / sizeof (struct dinode)) | |
b6407c9d | 16 | #define SPERB (MAXBSIZE / sizeof(short)) |
6e884967 KM |
17 | |
18 | #define MAXDUP 10 /* limit on dup blks (per inode) */ | |
19 | #define MAXBAD 10 /* limit on bad blks (per inode) */ | |
20 | ||
21 | #define USTATE 0 /* inode not allocated */ | |
22 | #define FSTATE 01 /* inode is file */ | |
23 | #define DSTATE 02 /* inode is directory */ | |
24 | #define CLEAR 03 /* inode is to be cleared */ | |
25 | ||
26 | typedef struct dinode DINODE; | |
27 | typedef struct direct DIRECT; | |
28 | ||
29 | #define ALLOC ((dp->di_mode & IFMT) != 0) | |
24a31719 | 30 | #define DIRCT ((dp->di_mode & IFMT) == IFDIR) |
6e884967 KM |
31 | #define REG ((dp->di_mode & IFMT) == IFREG) |
32 | #define BLK ((dp->di_mode & IFMT) == IFBLK) | |
33 | #define CHR ((dp->di_mode & IFMT) == IFCHR) | |
690f77ba | 34 | #define LNK ((dp->di_mode & IFMT) == IFLNK) |
ea47352d | 35 | #define SPECIAL (BLK || CHR) |
6e884967 | 36 | |
f3c028b7 | 37 | ino_t startinum; /* blk num of first in raw area */ |
6e884967 KM |
38 | |
39 | struct bufarea { | |
40 | struct bufarea *b_next; /* must be first */ | |
41 | daddr_t b_bno; | |
42 | int b_size; | |
43 | union { | |
b6407c9d | 44 | char b_buf[MAXBSIZE]; /* buffer space */ |
6e884967 | 45 | short b_lnks[SPERB]; /* link counts */ |
b6407c9d | 46 | daddr_t b_indir[MAXNINDIR]; /* indirect block */ |
6e884967 KM |
47 | struct fs b_fs; /* super block */ |
48 | struct cg b_cg; /* cylinder group */ | |
b6407c9d | 49 | struct dinode b_dinode[MAXINOPB]; /* inode block */ |
6e884967 KM |
50 | } b_un; |
51 | char b_dirty; | |
52 | }; | |
53 | ||
54 | typedef struct bufarea BUFAREA; | |
55 | ||
56 | BUFAREA inoblk; /* inode blocks */ | |
57 | BUFAREA fileblk; /* other blks in filesys */ | |
58 | BUFAREA sblk; /* file system superblock */ | |
59 | BUFAREA cgblk; | |
60 | ||
61 | #define initbarea(x) (x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1 | |
62 | #define dirty(x) (x)->b_dirty = 1 | |
63 | #define inodirty() inoblk.b_dirty = 1 | |
64 | #define sbdirty() sblk.b_dirty = 1 | |
65 | #define cgdirty() cgblk.b_dirty = 1 | |
66 | ||
67 | #define dirblk fileblk.b_un | |
68 | #define sblock sblk.b_un.b_fs | |
69 | #define cgrp cgblk.b_un.b_cg | |
70 | ||
71 | struct filecntl { | |
72 | int rfdes; | |
73 | int wfdes; | |
74 | int mod; | |
75 | } dfile; /* file descriptors for filesys */ | |
76 | ||
77 | #define DUPTBLSIZE 100 /* num of dup blocks to remember */ | |
78 | daddr_t duplist[DUPTBLSIZE]; /* dup block table */ | |
79 | daddr_t *enddup; /* next entry in dup table */ | |
80 | daddr_t *muldup; /* multiple dups part of table */ | |
81 | ||
690f77ba | 82 | #define MAXLNCNT 50 /* num zero link cnts to remember */ |
6e884967 KM |
83 | ino_t badlncnt[MAXLNCNT]; /* table of inos with zero link cnts */ |
84 | ino_t *badlnp; /* next entry in table */ | |
85 | ||
86 | char rawflg; | |
87 | char nflag; /* assume a no response */ | |
88 | char yflag; /* assume a yes response */ | |
89 | int bflag; /* location of alternate super block */ | |
6994bf5d | 90 | int debug; /* output debugging info */ |
6e884967 KM |
91 | char preen; /* just fix normal inconsistencies */ |
92 | char rplyflag; /* any questions asked? */ | |
93 | char hotroot; /* checking root device */ | |
94 | char fixcg; /* corrupted free list bit maps */ | |
95 | ||
79f5f76a | 96 | char *blockmap; /* ptr to primary blk allocation map */ |
6e884967 KM |
97 | char *freemap; /* ptr to secondary blk allocation map */ |
98 | char *statemap; /* ptr to inode state table */ | |
99 | short *lncntp; /* ptr to link count table */ | |
100 | ||
101 | char *pathp; /* pointer to pathname position */ | |
102 | char *thisname; /* ptr to current pathname component */ | |
103 | char *srchname; /* name being searched for in dir */ | |
24a31719 | 104 | char pathname[BUFSIZ]; |
6e884967 KM |
105 | |
106 | char *lfname = "lost+found"; | |
107 | ||
108 | ino_t inum; /* inode we are currently working on */ | |
6c6be8f1 | 109 | ino_t dnum; /* directory inode currently being worked on */ |
6e884967 KM |
110 | ino_t imax; /* number of inodes */ |
111 | ino_t parentdir; /* i number of parent directory */ | |
112 | ino_t lastino; /* hiwater mark of inodes */ | |
113 | ino_t lfdir; /* lost & found directory */ | |
114 | ino_t orphan; /* orphaned inode */ | |
115 | ||
116 | off_t filsize; /* num blks seen in file */ | |
117 | off_t maxblk; /* largest logical blk in file */ | |
79f5f76a | 118 | off_t bmapsz; /* num chars in blockmap */ |
6e884967 KM |
119 | |
120 | daddr_t n_ffree; /* number of small free blocks */ | |
121 | daddr_t n_bfree; /* number of large free blocks */ | |
122 | daddr_t n_blks; /* number of blocks used */ | |
123 | daddr_t n_files; /* number of files seen */ | |
124 | daddr_t n_index; | |
125 | daddr_t n_bad; | |
126 | daddr_t fmax; /* number of blocks in the volume */ | |
127 | ||
128 | daddr_t badblk; | |
129 | daddr_t dupblk; | |
130 | ||
131 | int inosumbad; | |
132 | int offsumbad; | |
f3c028b7 | 133 | int frsumbad; |
184d432f | 134 | int sbsumbad; |
6e884967 | 135 | |
6e884967 KM |
136 | #define zapino(x) (*(x) = zino) |
137 | struct dinode zino; | |
138 | ||
79f5f76a KM |
139 | #define setbmap(x) setbit(blockmap, x) |
140 | #define getbmap(x) isset(blockmap, x) | |
141 | #define clrbmap(x) clrbit(blockmap, x) | |
6e884967 KM |
142 | |
143 | #define setfmap(x) setbit(freemap, x) | |
144 | #define getfmap(x) isset(freemap, x) | |
145 | #define clrfmap(x) clrbit(freemap, x) | |
146 | ||
6e884967 KM |
147 | #define DATA 1 |
148 | #define ADDR 0 | |
149 | ||
150 | #define ALTERD 010 | |
151 | #define KEEPON 04 | |
152 | #define SKIP 02 | |
153 | #define STOP 01 | |
154 | ||
155 | int (*signal())(); | |
156 | long lseek(); | |
157 | time_t time(); | |
158 | DINODE *ginode(); | |
159 | BUFAREA *getblk(); | |
160 | int dirscan(); | |
161 | int findino(); | |
162 | int catch(); | |
163 | int mkentry(); | |
164 | int chgdd(); | |
d2c95d76 | 165 | int pass1check(), pass1bcheck(), pass2check(), pass4check(), pass5check(); |
6e884967 KM |
166 | int (*pfunc)(); |
167 | char *rawname(), *rindex(), *unrawname(); | |
97656a89 | 168 | extern int inside[], around[]; |
b6407c9d | 169 | extern unsigned char *fragtbl[]; |
6e884967 KM |
170 | |
171 | char *devname; | |
172 | ||
173 | main(argc, argv) | |
8ebf61ca KM |
174 | int argc; |
175 | char *argv[]; | |
6e884967 KM |
176 | { |
177 | struct fstab *fsp; | |
178 | int pid, passno, anygtr, sumstatus; | |
179 | ||
180 | sync(); | |
181 | while (--argc > 0 && **++argv == '-') { | |
182 | switch (*++*argv) { | |
183 | ||
184 | case 'p': | |
185 | preen++; | |
186 | break; | |
187 | ||
188 | case 'b': | |
189 | bflag = atoi(argv[0]+1); | |
190 | printf("Alternate super block location: %d\n", bflag); | |
191 | break; | |
192 | ||
6994bf5d KM |
193 | case 'd': |
194 | debug++; | |
195 | break; | |
196 | ||
6e884967 KM |
197 | case 'n': /* default no answer flag */ |
198 | case 'N': | |
199 | nflag++; | |
200 | yflag = 0; | |
201 | break; | |
202 | ||
203 | case 'y': /* default yes answer flag */ | |
204 | case 'Y': | |
205 | yflag++; | |
206 | nflag = 0; | |
207 | break; | |
208 | ||
209 | default: | |
210 | errexit("%c option?\n", **argv); | |
211 | } | |
212 | } | |
213 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) | |
214 | signal(SIGINT, catch); | |
215 | if (argc) { | |
216 | while (argc-- > 0) { | |
217 | hotroot = 0; | |
d2c95d76 | 218 | checkfilesys(*argv++); |
6e884967 KM |
219 | } |
220 | exit(0); | |
221 | } | |
222 | sumstatus = 0; | |
223 | passno = 1; | |
224 | do { | |
225 | anygtr = 0; | |
226 | if (setfsent() == 0) | |
227 | errexit("Can't open checklist file: %s\n", FSTAB); | |
228 | while ((fsp = getfsent()) != 0) { | |
229 | if (strcmp(fsp->fs_type, FSTAB_RW) && | |
230 | strcmp(fsp->fs_type, FSTAB_RO)) | |
231 | continue; | |
232 | if (preen == 0 || | |
233 | passno == 1 && fsp->fs_passno == passno) { | |
234 | if (blockcheck(fsp->fs_spec) == 0 && preen) | |
235 | exit(8); | |
236 | } else if (fsp->fs_passno > passno) | |
237 | anygtr = 1; | |
238 | else if (fsp->fs_passno == passno) { | |
239 | pid = fork(); | |
240 | if (pid < 0) { | |
241 | perror("fork"); | |
242 | exit(8); | |
243 | } | |
244 | if (pid == 0) | |
245 | if (blockcheck(fsp->fs_spec)==0) | |
246 | exit(8); | |
247 | else | |
248 | exit(0); | |
249 | } | |
250 | } | |
251 | if (preen) { | |
252 | int status; | |
253 | while (wait(&status) != -1) | |
254 | sumstatus |= status; | |
255 | } | |
256 | passno++; | |
257 | } while (anygtr); | |
258 | if (sumstatus) | |
259 | exit(8); | |
260 | endfsent(); | |
261 | exit(0); | |
262 | } | |
263 | ||
264 | blockcheck(name) | |
265 | char *name; | |
266 | { | |
4d308541 | 267 | struct stat stslash, stblock, stchar; |
6e884967 KM |
268 | char *raw; |
269 | int looped = 0; | |
270 | ||
271 | hotroot = 0; | |
272 | if (stat("/", &stslash) < 0){ | |
273 | error("Can't stat root\n"); | |
274 | return (0); | |
275 | } | |
276 | retry: | |
277 | if (stat(name, &stblock) < 0){ | |
278 | error("Can't stat %s\n", name); | |
279 | return (0); | |
280 | } | |
281 | if (stblock.st_mode & S_IFBLK) { | |
282 | raw = rawname(name); | |
283 | if (stat(raw, &stchar) < 0){ | |
284 | error("Can't stat %s\n", raw); | |
285 | return (0); | |
286 | } | |
287 | if (stchar.st_mode & S_IFCHR) { | |
288 | if (stslash.st_dev == stblock.st_rdev) { | |
289 | hotroot++; | |
290 | raw = unrawname(name); | |
291 | } | |
d2c95d76 | 292 | checkfilesys(raw); |
6e884967 KM |
293 | return (1); |
294 | } else { | |
295 | error("%s is not a character device\n", raw); | |
296 | return (0); | |
297 | } | |
298 | } else if (stblock.st_mode & S_IFCHR) { | |
299 | if (looped) { | |
300 | error("Can't make sense out of name %s\n", name); | |
301 | return (0); | |
302 | } | |
303 | name = unrawname(name); | |
304 | looped++; | |
305 | goto retry; | |
306 | } | |
307 | error("Can't make sense out of name %s\n", name); | |
308 | return (0); | |
309 | } | |
310 | ||
d2c95d76 BJ |
311 | checkfilesys(filesys) |
312 | char *filesys; | |
6e884967 KM |
313 | { |
314 | register DINODE *dp; | |
315 | register ino_t *blp; | |
316 | register int i, n; | |
317 | ino_t savino; | |
6bccc723 | 318 | int b, c, j, partial, ndb; |
6e884967 KM |
319 | daddr_t d, s; |
320 | ||
d2c95d76 BJ |
321 | devname = filesys; |
322 | if (setup(filesys) == 0) { | |
6e884967 | 323 | if (preen) |
d2c95d76 | 324 | pfatal("CAN'T CHECK FILE SYSTEM."); |
6e884967 KM |
325 | return; |
326 | } | |
d2c95d76 | 327 | /* 1: scan inodes tallying blocks used */ |
690f77ba KM |
328 | if (preen == 0) { |
329 | printf("** Last Mounted on %s\n", sblock.fs_fsmnt); | |
6e884967 KM |
330 | if (hotroot) |
331 | printf("** Root file system\n"); | |
332 | printf("** Phase 1 - Check Blocks and Sizes\n"); | |
333 | } | |
d2c95d76 BJ |
334 | pass1(); |
335 | ||
336 | /* 1b: locate first references to duplicates, if any */ | |
337 | if (enddup != &duplist[0]) { | |
338 | if (preen) | |
339 | pfatal("INTERNAL ERROR: dups with -p"); | |
340 | printf("** Phase 1b - Rescan For More DUPS\n"); | |
341 | pass1b(); | |
342 | } | |
343 | ||
344 | /* 2: traverse directories to check reference counts */ | |
345 | if (preen == 0) | |
346 | printf("** Phase 2 - Check Pathnames\n"); | |
347 | pass2(); | |
348 | ||
349 | /* 3 */ | |
350 | if (preen == 0) | |
351 | printf("** Phase 3 - Check Connectivity\n"); | |
352 | pass3(); | |
353 | ||
354 | /* 4 */ | |
355 | if (preen == 0) | |
356 | printf("** Phase 4 - Check Reference Counts\n"); | |
357 | pass4(); | |
358 | ||
359 | /* 5 */ | |
360 | if (preen == 0) | |
361 | printf("** Phase 5 - Check Cyl groups\n"); | |
362 | pass5(); | |
363 | ||
364 | if (fixcg) { | |
365 | if (preen == 0) | |
366 | printf("** Phase 6 - Salvage Cylinder Groups\n"); | |
367 | makecg(); | |
368 | n_ffree = sblock.fs_cstotal.cs_nffree; | |
369 | n_bfree = sblock.fs_cstotal.cs_nbfree; | |
370 | } | |
371 | ||
372 | pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n", | |
373 | n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_fsize), | |
374 | n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree); | |
375 | if (dfile.mod) { | |
376 | time(&sblock.fs_time); | |
377 | sbdirty(); | |
378 | } | |
379 | ckfini(); | |
380 | free(blockmap); | |
381 | free(freemap); | |
382 | free(statemap); | |
383 | free(lncntp); | |
384 | if (dfile.mod) | |
385 | if (preen) { | |
386 | printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); | |
387 | if (hotroot) { | |
388 | sync(); | |
389 | exit(4); | |
390 | } | |
391 | } else if (hotroot) { | |
392 | printf("\n***** BOOT UNIX (NO SYNC!) *****\n"); | |
393 | exit(4); | |
394 | } | |
395 | sync(); | |
396 | } | |
397 | ||
398 | pass1() | |
399 | { | |
400 | register int c, i, n, j; | |
401 | register DINODE *dp; | |
402 | int savino, ndb, partial; | |
403 | ||
404 | pfunc = pass1check; | |
6e884967 | 405 | inum = 0; |
bf541624 | 406 | n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); |
6e884967 | 407 | for (c = 0; c < sblock.fs_ncg; c++) { |
6994bf5d | 408 | if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0) |
6e884967 | 409 | continue; |
bf541624 KM |
410 | if (debug && cgrp.cg_magic != CG_MAGIC) |
411 | printf("cg %d: bad magic number\n", c); | |
6e884967 | 412 | n = 0; |
f3c028b7 KM |
413 | for (i = 0; i < sblock.fs_ipg; i++, inum++) { |
414 | dp = ginode(); | |
415 | if (dp == NULL) | |
416 | continue; | |
bf4c734c | 417 | n++; |
6e884967 KM |
418 | if (ALLOC) { |
419 | if (!isset(cgrp.cg_iused, i)) { | |
6994bf5d KM |
420 | if (debug) |
421 | printf("%d bad, not used\n", | |
422 | inum); | |
6e884967 KM |
423 | inosumbad++; |
424 | } | |
bf4c734c | 425 | n--; |
6e884967 | 426 | lastino = inum; |
6bccc723 KM |
427 | if (ftypeok(dp) == 0) |
428 | goto unknown; | |
429 | if (dp->di_size < 0) | |
430 | goto unknown; | |
431 | ndb = howmany(dp->di_size, sblock.fs_bsize); | |
432 | if (SPECIAL) | |
433 | ndb++; | |
434 | for (j = ndb; j < NDADDR; j++) | |
435 | if (dp->di_db[j] != 0) | |
436 | goto unknown; | |
437 | for (j = 0, ndb -= NDADDR; ndb > 0; j++) | |
438 | ndb /= NINDIR(&sblock); | |
439 | for (; j < NIADDR; j++) | |
440 | if (dp->di_ib[j] != 0) | |
441 | goto unknown; | |
6e884967 | 442 | n_files++; |
f5262822 BJ |
443 | lncntp[inum] = dp->di_nlink; |
444 | if (dp->di_nlink <= 0) { | |
6e884967 KM |
445 | if (badlnp < &badlncnt[MAXLNCNT]) |
446 | *badlnp++ = inum; | |
447 | else { | |
448 | pfatal("LINK COUNT TABLE OVERFLOW"); | |
449 | if (reply("CONTINUE") == 0) | |
450 | errexit(""); | |
451 | } | |
452 | } | |
f5262822 | 453 | statemap[inum] = DIRCT ? DSTATE : FSTATE; |
6e884967 KM |
454 | badblk = dupblk = 0; filsize = 0; maxblk = 0; |
455 | ckinode(dp, ADDR); | |
6bccc723 KM |
456 | continue; |
457 | unknown: | |
458 | pfatal("UNKNOWN FILE TYPE I=%u", inum); | |
459 | if (reply("CLEAR") == 1) { | |
460 | zapino(dp); | |
461 | inodirty(); | |
462 | inosumbad++; | |
463 | } | |
6e884967 | 464 | } else { |
6e884967 | 465 | if (isset(cgrp.cg_iused, i)) { |
6994bf5d KM |
466 | if (debug) |
467 | printf("%d bad, marked used\n", | |
468 | inum); | |
6e884967 | 469 | inosumbad++; |
f3c028b7 | 470 | n--; |
6e884967 | 471 | } |
6bccc723 KM |
472 | partial = 0; |
473 | for (j = 0; j < NDADDR; j++) | |
474 | if (dp->di_db[j] != 0) | |
475 | partial++; | |
476 | for (j = 0; j < NIADDR; j++) | |
477 | if (dp->di_ib[j] != 0) | |
478 | partial++; | |
479 | if (partial || dp->di_mode != 0 || | |
480 | dp->di_size != 0) { | |
6e884967 KM |
481 | pfatal("PARTIALLY ALLOCATED INODE I=%u", inum); |
482 | if (reply("CLEAR") == 1) { | |
483 | zapino(dp); | |
484 | inodirty(); | |
485 | inosumbad++; | |
486 | } | |
487 | } | |
488 | } | |
489 | } | |
0947395d | 490 | if (n != cgrp.cg_cs.cs_nifree) { |
6994bf5d | 491 | if (debug) |
bf4c734c | 492 | printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n", |
6994bf5d | 493 | c, cgrp.cg_cs.cs_nifree, n); |
6e884967 KM |
494 | inosumbad++; |
495 | } | |
184d432f KM |
496 | if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree |
497 | || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree | |
498 | || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree | |
499 | || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir) | |
500 | sbsumbad++; | |
6e884967 | 501 | } |
d2c95d76 BJ |
502 | } |
503 | ||
504 | pass1check(blk, size) | |
505 | daddr_t blk; | |
506 | int size; | |
507 | { | |
508 | register daddr_t *dlp; | |
509 | int res = KEEPON; | |
510 | ||
511 | for (; size > 0; blk++, size--) { | |
512 | if (outrange(blk)) { | |
513 | blkerr("BAD", blk); | |
514 | if (++badblk >= MAXBAD) { | |
515 | pwarn("EXCESSIVE BAD BLKS I=%u", inum); | |
516 | if (preen) | |
517 | printf(" (SKIPPING)\n"); | |
518 | else if (reply("CONTINUE") == 0) | |
519 | errexit(""); | |
520 | return (STOP); | |
521 | } | |
522 | res = SKIP; | |
523 | } else if (getbmap(blk)) { | |
524 | blkerr("DUP", blk); | |
525 | if (++dupblk >= MAXDUP) { | |
526 | pwarn("EXCESSIVE DUP BLKS I=%u", inum); | |
527 | if (preen) | |
528 | printf(" (SKIPPING)\n"); | |
529 | else if (reply("CONTINUE") == 0) | |
530 | errexit(""); | |
531 | return (STOP); | |
532 | } | |
533 | if (enddup >= &duplist[DUPTBLSIZE]) { | |
534 | pfatal("DUP TABLE OVERFLOW."); | |
535 | if (reply("CONTINUE") == 0) | |
536 | errexit(""); | |
537 | return (STOP); | |
538 | } | |
539 | for (dlp = duplist; dlp < muldup; dlp++) | |
540 | if (*dlp == blk) { | |
541 | *enddup++ = blk; | |
542 | break; | |
543 | } | |
544 | if (dlp >= muldup) { | |
545 | *enddup++ = *muldup; | |
546 | *muldup++ = blk; | |
f3c028b7 | 547 | } |
d2c95d76 BJ |
548 | } else { |
549 | n_blks++; | |
550 | setbmap(blk); | |
551 | } | |
552 | filsize++; | |
553 | } | |
554 | return (res); | |
555 | } | |
556 | ||
557 | pass1b() | |
558 | { | |
559 | register int c, i; | |
560 | register DINODE *dp; | |
561 | ||
562 | pfunc = pass1bcheck; | |
563 | inum = 0; | |
564 | for (c = 0; c < sblock.fs_ncg; c++) { | |
565 | for (i = 0; i < sblock.fs_ipg; i++, inum++) { | |
566 | dp = ginode(); | |
567 | if (dp == NULL) | |
568 | continue; | |
f5262822 | 569 | if (statemap[inum] != USTATE && |
d2c95d76 BJ |
570 | (ckinode(dp, ADDR) & STOP)) |
571 | goto out1b; | |
6e884967 KM |
572 | } |
573 | } | |
574 | out1b: | |
f3c028b7 | 575 | flush(&dfile, &inoblk); |
d2c95d76 BJ |
576 | } |
577 | ||
578 | pass1bcheck(blk, size) | |
579 | daddr_t blk; | |
580 | int size; | |
581 | { | |
582 | register daddr_t *dlp; | |
583 | int res = KEEPON; | |
584 | ||
585 | for (; size > 0; blk++, size--) { | |
586 | if (outrange(blk)) | |
587 | res = SKIP; | |
588 | for (dlp = duplist; dlp < muldup; dlp++) | |
589 | if (*dlp == blk) { | |
590 | blkerr("DUP", blk); | |
591 | *dlp = *--muldup; | |
592 | *muldup = blk; | |
593 | if (muldup == duplist) | |
594 | return (STOP); | |
595 | } | |
596 | } | |
597 | return (res); | |
598 | } | |
599 | ||
600 | pass2() | |
601 | { | |
602 | register DINODE *dp; | |
603 | ||
6e884967 KM |
604 | inum = ROOTINO; |
605 | thisname = pathp = pathname; | |
d2c95d76 | 606 | pfunc = pass2check; |
f5262822 | 607 | switch (statemap[inum]) { |
6e884967 KM |
608 | |
609 | case USTATE: | |
610 | errexit("ROOT INODE UNALLOCATED. TERMINATING.\n"); | |
611 | ||
612 | case FSTATE: | |
613 | pfatal("ROOT INODE NOT DIRECTORY"); | |
614 | if (reply("FIX") == 0 || (dp = ginode()) == NULL) | |
615 | errexit(""); | |
616 | dp->di_mode &= ~IFMT; | |
617 | dp->di_mode |= IFDIR; | |
618 | inodirty(); | |
619 | inosumbad++; | |
f5262822 | 620 | statemap[inum] = DSTATE; |
6e884967 KM |
621 | /* fall into ... */ |
622 | ||
623 | case DSTATE: | |
624 | descend(); | |
625 | break; | |
626 | ||
627 | case CLEAR: | |
628 | pfatal("DUPS/BAD IN ROOT INODE"); | |
629 | printf("\n"); | |
630 | if (reply("CONTINUE") == 0) | |
631 | errexit(""); | |
f5262822 | 632 | statemap[inum] = DSTATE; |
6e884967 KM |
633 | descend(); |
634 | } | |
d2c95d76 BJ |
635 | } |
636 | ||
637 | pass2check(dirp) | |
638 | register DIRECT *dirp; | |
639 | { | |
640 | register char *p; | |
641 | register n; | |
642 | DINODE *dp; | |
643 | ||
644 | if ((inum = dirp->d_ino) == 0) | |
645 | return (KEEPON); | |
646 | thisname = pathp; | |
647 | for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; ) | |
648 | if ((*pathp++ = *p++) == 0) { | |
649 | --pathp; | |
650 | break; | |
651 | } | |
652 | *pathp = 0; | |
653 | n = 0; | |
654 | if (inum > imax || inum <= 0) | |
655 | n = direrr("I OUT OF RANGE"); | |
656 | else { | |
657 | again: | |
f5262822 | 658 | switch (statemap[inum]) { |
d2c95d76 BJ |
659 | case USTATE: |
660 | n = direrr("UNALLOCATED"); | |
661 | break; | |
662 | ||
663 | case CLEAR: | |
664 | if ((n = direrr("DUP/BAD")) == 1) | |
665 | break; | |
666 | if ((dp = ginode()) == NULL) | |
667 | break; | |
f5262822 | 668 | statemap[inum] = DIRCT ? DSTATE : FSTATE; |
d2c95d76 BJ |
669 | goto again; |
670 | ||
671 | case FSTATE: | |
f5262822 | 672 | lncntp[inum]--; |
d2c95d76 BJ |
673 | break; |
674 | ||
675 | case DSTATE: | |
f5262822 | 676 | lncntp[inum]--; |
d2c95d76 BJ |
677 | descend(); |
678 | break; | |
679 | } | |
680 | } | |
681 | pathp = thisname; | |
682 | if (n == 0) | |
683 | return (KEEPON); | |
684 | dirp->d_ino = 0; | |
685 | return (KEEPON|ALTERD); | |
686 | } | |
687 | ||
688 | pass3() | |
689 | { | |
690 | ino_t savino; | |
691 | register DINODE *dp; | |
692 | ||
6e884967 | 693 | for (inum = ROOTINO; inum <= lastino; inum++) { |
f5262822 | 694 | if (statemap[inum] == DSTATE) { |
6e884967 KM |
695 | pfunc = findino; |
696 | srchname = ".."; | |
697 | savino = inum; | |
698 | do { | |
699 | orphan = inum; | |
700 | if ((dp = ginode()) == NULL) | |
701 | break; | |
702 | filsize = dp->di_size; | |
703 | parentdir = 0; | |
704 | ckinode(dp, DATA); | |
705 | if ((inum = parentdir) == 0) | |
706 | break; | |
f5262822 | 707 | } while (statemap[inum] == DSTATE); |
6e884967 KM |
708 | inum = orphan; |
709 | if (linkup() == 1) { | |
710 | thisname = pathp = pathname; | |
711 | *pathp++ = '?'; | |
d2c95d76 | 712 | pfunc = pass2check; |
6e884967 KM |
713 | descend(); |
714 | } | |
715 | inum = savino; | |
716 | } | |
717 | } | |
d2c95d76 | 718 | } |
6e884967 | 719 | |
d2c95d76 BJ |
720 | pass4() |
721 | { | |
722 | register int n; | |
723 | register ino_t *blp; | |
724 | ||
725 | pfunc = pass4check; | |
726 | for (inum = ROOTINO; inum <= lastino; inum++) { | |
f5262822 | 727 | switch (statemap[inum]) { |
d2c95d76 BJ |
728 | |
729 | case FSTATE: | |
f5262822 BJ |
730 | n = lncntp[inum]; |
731 | if (n) | |
6e884967 KM |
732 | adjust((short)n); |
733 | else { | |
734 | for (blp = badlncnt;blp < badlnp; blp++) | |
735 | if (*blp == inum) { | |
736 | clri("UNREF", 1); | |
737 | break; | |
738 | } | |
739 | } | |
740 | break; | |
741 | ||
742 | case DSTATE: | |
743 | clri("UNREF", 1); | |
744 | break; | |
745 | ||
746 | case CLEAR: | |
747 | clri("BAD/DUP", 1); | |
748 | break; | |
749 | } | |
750 | } | |
8e5c1c7c | 751 | if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) { |
6e884967 KM |
752 | pwarn("FREE INODE COUNT WRONG IN SUPERBLK"); |
753 | if (preen) | |
754 | printf(" (FIXED)\n"); | |
755 | if (preen || reply("FIX") == 1) { | |
bf4c734c | 756 | sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files; |
6e884967 KM |
757 | sbdirty(); |
758 | } | |
759 | } | |
760 | flush(&dfile, &fileblk); | |
d2c95d76 | 761 | } |
6e884967 | 762 | |
d2c95d76 BJ |
763 | pass4check(blk, size) |
764 | daddr_t blk; | |
765 | { | |
766 | register daddr_t *dlp; | |
767 | int res = KEEPON; | |
768 | ||
769 | for (; size > 0; blk++, size--) { | |
770 | if (outrange(blk)) | |
771 | res = SKIP; | |
772 | else if (getbmap(blk)) { | |
773 | for (dlp = duplist; dlp < enddup; dlp++) | |
774 | if (*dlp == blk) { | |
775 | *dlp = *--enddup; | |
776 | return (KEEPON); | |
777 | } | |
778 | clrbmap(blk); | |
779 | n_blks--; | |
780 | } | |
781 | } | |
782 | return (res); | |
783 | } | |
784 | ||
785 | pass5() | |
786 | { | |
787 | register int c, n, i, b, d; | |
788 | ||
789 | blkcpy((unsigned)bmapsz, blockmap, freemap); | |
6e884967 | 790 | dupblk = 0; |
6994bf5d | 791 | n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0)); |
6e884967 | 792 | for (c = 0; c < sblock.fs_ncg; c++) { |
6994bf5d | 793 | daddr_t cbase = cgbase(&sblock, c); |
6e884967 | 794 | short bo[MAXCPG][NRPOS]; |
43f6367c | 795 | long botot[MAXCPG]; |
b6407c9d | 796 | long frsum[MAXFRAG]; |
f3c028b7 KM |
797 | int blk; |
798 | ||
43f6367c KM |
799 | for (n = 0; n < sblock.fs_cpg; n++) { |
800 | botot[n] = 0; | |
6e884967 KM |
801 | for (i = 0; i < NRPOS; i++) |
802 | bo[n][i] = 0; | |
43f6367c | 803 | } |
d2c95d76 | 804 | for (i = 0; i < sblock.fs_frag; i++) |
f3c028b7 | 805 | frsum[i] = 0; |
f3c028b7 | 806 | /* |
bf541624 | 807 | * need to account for the super blocks |
f3c028b7 KM |
808 | * which appear (inaccurately) bad |
809 | */ | |
bf541624 | 810 | n_bad += cgtod(&sblock, c) - cgsblock(&sblock, c); |
6994bf5d | 811 | if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0) |
6e884967 | 812 | continue; |
bf541624 KM |
813 | if (debug && cgrp.cg_magic != CG_MAGIC) |
814 | printf("cg %d: bad magic number\n", c); | |
b6407c9d KM |
815 | for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) { |
816 | if (isblock(&sblock, cgrp.cg_free, b/sblock.fs_frag)) { | |
d2c95d76 | 817 | if (pass5check(cbase+b, sblock.fs_frag) == STOP) |
6e884967 KM |
818 | goto out5; |
819 | /* this is clumsy ... */ | |
d2c95d76 BJ |
820 | n_ffree -= sblock.fs_frag; |
821 | n_bfree++; | |
822 | botot[cbtocylno(&sblock, b)]++; | |
823 | bo[cbtocylno(&sblock, b)] | |
824 | [cbtorpos(&sblock, b)]++; | |
825 | } else { | |
826 | for (d = 0; d < sblock.fs_frag; d++) | |
827 | if (isset(cgrp.cg_free, b+d)) | |
828 | if (pass5check(cbase+b+d,1) == STOP) | |
829 | goto out5; | |
830 | blk = ((cgrp.cg_free[b / NBBY] >> (b % NBBY)) & | |
831 | (0xff >> (NBBY - sblock.fs_frag))); | |
832 | if (blk != 0) | |
833 | fragacct(&sblock, blk, frsum, 1); | |
834 | } | |
6e884967 | 835 | } |
d2c95d76 BJ |
836 | for (i = 0; i < sblock.fs_frag; i++) { |
837 | if (cgrp.cg_frsum[i] != frsum[i]) { | |
838 | if (debug) | |
839 | printf("cg[%d].cg_frsum[%d] have %d calc %d\n", | |
840 | c, i, cgrp.cg_frsum[i], frsum[i]); | |
841 | frsumbad++; | |
842 | } | |
843 | } | |
844 | for (n = 0; n < sblock.fs_cpg; n++) { | |
845 | if (botot[n] != cgrp.cg_btot[n]) { | |
846 | if (debug) | |
847 | printf("cg[%d].cg_btot[%d] have %d calc %d\n", | |
848 | c, n, cgrp.cg_btot[n], botot[n]); | |
849 | offsumbad++; | |
850 | } | |
851 | for (i = 0; i < NRPOS; i++) | |
852 | if (bo[n][i] != cgrp.cg_b[n][i]) { | |
853 | if (debug) | |
854 | printf("cg[%d].cg_b[%d][%d] have %d calc %d\n", | |
855 | c, n, i, cgrp.cg_b[n][i], | |
856 | bo[n][i]); | |
857 | offsumbad++; | |
6e884967 | 858 | } |
6e884967 KM |
859 | } |
860 | } | |
d2c95d76 BJ |
861 | out5: |
862 | if (dupblk) | |
863 | pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk); | |
864 | if (fixcg == 0) { | |
865 | if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) { | |
866 | pwarn("%ld BLK(S) MISSING\n", fmax - b); | |
867 | fixcg = 1; | |
868 | } else if (inosumbad + offsumbad + frsumbad + sbsumbad) { | |
869 | pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n", | |
870 | inosumbad ? "(INODE FREE) " : "", | |
871 | offsumbad ? "(BLOCK OFFSETS) " : "", | |
872 | frsumbad ? "(FRAG SUMMARIES) " : "", | |
873 | sbsumbad ? "(SUPER BLOCK SUMMARIES) " : ""); | |
874 | fixcg = 1; | |
875 | } else if (n_ffree != sblock.fs_cstotal.cs_nffree || | |
876 | n_bfree != sblock.fs_cstotal.cs_nbfree) { | |
877 | pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK"); | |
878 | if (preen) | |
879 | printf(" (FIXED)\n"); | |
880 | if (preen || reply("FIX") == 1) { | |
881 | sblock.fs_cstotal.cs_nffree = n_ffree; | |
882 | sblock.fs_cstotal.cs_nbfree = n_bfree; | |
883 | sbdirty(); | |
884 | } | |
885 | } | |
886 | } | |
887 | if (fixcg) { | |
888 | pwarn("BAD CYLINDER GROUPS"); | |
889 | if (preen) | |
890 | printf(" (SALVAGED)\n"); | |
891 | else if (reply("SALVAGE") == 0) | |
892 | fixcg = 0; | |
893 | } | |
6e884967 KM |
894 | } |
895 | ||
d2c95d76 | 896 | pass5check(blk, size) |
6e884967 KM |
897 | daddr_t blk; |
898 | int size; | |
899 | { | |
900 | int res = KEEPON; | |
901 | ||
902 | for (; size > 0; blk++, size--) { | |
903 | if (outrange(blk)) { | |
904 | fixcg = 1; | |
905 | if (preen) | |
906 | pfatal("BAD BLOCKS IN BIT MAPS."); | |
907 | if (++badblk >= MAXBAD) { | |
908 | printf("EXCESSIVE BAD BLKS IN BIT MAPS."); | |
909 | if (reply("CONTINUE") == 0) | |
910 | errexit(""); | |
911 | return (STOP); | |
912 | } | |
913 | } else if (getfmap(blk)) { | |
914 | fixcg = 1; | |
7ebb5f4e | 915 | ++dupblk; |
6e884967 KM |
916 | } else { |
917 | n_ffree++; | |
918 | setfmap(blk); | |
919 | } | |
920 | } | |
921 | return (res); | |
922 | } | |
923 | ||
d2c95d76 BJ |
924 | ckinode(dp, flg) |
925 | DINODE *dp; | |
926 | register flg; | |
927 | { | |
928 | register daddr_t *ap; | |
929 | register ret; | |
930 | int (*func)(), n, ndb, size, offset; | |
931 | ino_t number = inum; | |
932 | DINODE dino; | |
933 | ||
934 | if (SPECIAL) | |
935 | return (KEEPON); | |
936 | dino = *dp; | |
937 | func = (flg == ADDR) ? pfunc : dirscan; | |
938 | ndb = howmany(dino.di_size, sblock.fs_bsize); | |
939 | for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { | |
940 | if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) | |
941 | size = numfrags(&sblock, fragroundup(&sblock, offset)); | |
942 | else | |
943 | size = sblock.fs_frag; | |
944 | dnum = number; | |
945 | if (*ap && (ret = (*func)(*ap, size)) & STOP) | |
946 | return (ret); | |
947 | } | |
948 | for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) { | |
949 | dnum = number; | |
950 | if (*ap) { | |
951 | ret = iblock(*ap, n, flg, | |
952 | dino.di_size - sblock.fs_bsize * NDADDR); | |
953 | if (ret & STOP) | |
954 | return (ret); | |
955 | } | |
956 | } | |
957 | return (KEEPON); | |
958 | } | |
959 | ||
960 | iblock(blk, ilevel, flg, isize) | |
961 | daddr_t blk; | |
962 | register ilevel; | |
963 | int isize; | |
964 | { | |
965 | register daddr_t *ap; | |
966 | register daddr_t *aplim; | |
967 | register int i, n; | |
968 | int (*func)(), nif; | |
969 | BUFAREA ib; | |
970 | ||
971 | if (flg == ADDR) { | |
972 | func = pfunc; | |
973 | if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0) | |
974 | return (n); | |
975 | } else | |
976 | func = dirscan; | |
977 | if (outrange(blk)) /* protect thyself */ | |
978 | return (SKIP); | |
979 | initbarea(&ib); | |
980 | if (getblk(&ib, blk, sblock.fs_bsize) == NULL) | |
981 | return (SKIP); | |
982 | ilevel--; | |
983 | if (ilevel == 0) { | |
984 | nif = lblkno(&sblock, isize) + 1; | |
985 | } else /* ilevel == 1 */ { | |
986 | nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1; | |
987 | } | |
988 | if (nif > NINDIR(&sblock)) | |
989 | nif = NINDIR(&sblock); | |
990 | aplim = &ib.b_un.b_indir[nif]; | |
991 | for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++) | |
992 | if (*ap) { | |
993 | if (ilevel > 0) | |
994 | n = iblock(*ap, ilevel, flg, | |
995 | isize - i*NINDIR(&sblock)*sblock.fs_bsize); | |
996 | else | |
997 | n = (*func)(*ap, sblock.fs_frag); | |
998 | if (n & STOP) | |
999 | return (n); | |
1000 | } | |
1001 | return (KEEPON); | |
1002 | } | |
1003 | ||
6e884967 KM |
1004 | outrange(blk) |
1005 | daddr_t blk; | |
1006 | { | |
1007 | register int c; | |
1008 | ||
6994bf5d | 1009 | c = dtog(&sblock, blk); |
bf541624 | 1010 | if ((unsigned)blk >= fmax) { |
6e884967 | 1011 | return (1); |
07670f7d | 1012 | } |
6e884967 KM |
1013 | return (0); |
1014 | } | |
1015 | ||
1016 | blkerr(s, blk) | |
1017 | daddr_t blk; | |
1018 | char *s; | |
1019 | { | |
f5262822 | 1020 | |
6e884967 KM |
1021 | pfatal("%ld %s I=%u", blk, s, inum); |
1022 | printf("\n"); | |
f5262822 | 1023 | statemap[inum] = CLEAR; |
6e884967 KM |
1024 | } |
1025 | ||
1026 | descend() | |
1027 | { | |
1028 | register DINODE *dp; | |
1029 | register char *savname; | |
1030 | off_t savsize; | |
1031 | ||
f5262822 | 1032 | statemap[inum] = FSTATE; |
6e884967 KM |
1033 | if ((dp = ginode()) == NULL) |
1034 | return; | |
1035 | savname = thisname; | |
1036 | *pathp++ = '/'; | |
1037 | savsize = filsize; | |
1038 | filsize = dp->di_size; | |
1039 | ckinode(dp, DATA); | |
1040 | thisname = savname; | |
1041 | *--pathp = 0; | |
1042 | filsize = savsize; | |
1043 | } | |
1044 | ||
24a31719 KM |
1045 | struct dirstuff { |
1046 | int loc; | |
1047 | int blkno; | |
1048 | int blksiz; | |
6c6be8f1 | 1049 | ino_t number; |
cf8ac751 | 1050 | enum {DONTKNOW, NOFIX, FIX} fix; |
24a31719 KM |
1051 | }; |
1052 | ||
6e884967 | 1053 | dirscan(blk, nf) |
8ebf61ca KM |
1054 | daddr_t blk; |
1055 | int nf; | |
6e884967 | 1056 | { |
24a31719 | 1057 | register DIRECT *dp; |
24a31719 | 1058 | struct dirstuff dirp; |
754cadb5 KM |
1059 | int blksiz, dsize, n; |
1060 | char dbuf[DIRBLKSIZ]; | |
6e884967 KM |
1061 | |
1062 | if (outrange(blk)) { | |
b6407c9d | 1063 | filsize -= sblock.fs_bsize; |
6e884967 KM |
1064 | return (SKIP); |
1065 | } | |
24a31719 KM |
1066 | blksiz = nf * sblock.fs_fsize; |
1067 | dirp.loc = 0; | |
1068 | dirp.blkno = blk; | |
1069 | dirp.blksiz = blksiz; | |
690f77ba KM |
1070 | if (dirp.number != dnum) { |
1071 | dirp.number = dnum; | |
cf8ac751 | 1072 | dirp.fix = DONTKNOW; |
690f77ba | 1073 | } |
24a31719 | 1074 | for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) { |
754cadb5 | 1075 | dsize = dp->d_reclen; |
d2c95d76 | 1076 | bcopy(dp, dbuf, dsize); |
754cadb5 | 1077 | if ((n = (*pfunc)(dbuf)) & ALTERD) { |
24a31719 | 1078 | if (getblk(&fileblk, blk, blksiz) != NULL) { |
d2c95d76 | 1079 | bcopy(dbuf, dp, dsize); |
8ebf61ca | 1080 | dirty(&fileblk); |
6e884967 KM |
1081 | sbdirty(); |
1082 | } else | |
1083 | n &= ~ALTERD; | |
1084 | } | |
24a31719 | 1085 | if (n & STOP) |
6e884967 KM |
1086 | return (n); |
1087 | } | |
1088 | return (filsize > 0 ? KEEPON : STOP); | |
1089 | } | |
1090 | ||
24a31719 KM |
1091 | /* |
1092 | * get next entry in a directory. | |
1093 | */ | |
1094 | DIRECT * | |
1095 | readdir(dirp) | |
1096 | register struct dirstuff *dirp; | |
1097 | { | |
754cadb5 | 1098 | register DIRECT *dp, *ndp; |
690f77ba | 1099 | long size; |
24a31719 KM |
1100 | |
1101 | if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) { | |
1102 | filsize -= dirp->blksiz - dirp->loc; | |
1103 | return NULL; | |
1104 | } | |
690f77ba KM |
1105 | while (dirp->loc % DIRBLKSIZ == 0 && filsize > 0 && |
1106 | dirp->loc < dirp->blksiz) { | |
052efd62 | 1107 | dp = (DIRECT *)(dirblk.b_buf + dirp->loc); |
690f77ba KM |
1108 | if (dp->d_ino < imax && |
1109 | dp->d_namlen <= MAXNAMLEN && dp->d_namlen >= 0 && | |
1110 | dp->d_reclen > 0 && dp->d_reclen <= DIRBLKSIZ) | |
1111 | break; | |
1112 | dirp->loc += DIRBLKSIZ; | |
1113 | filsize -= DIRBLKSIZ; | |
cf8ac751 | 1114 | if (dirp->fix == DONTKNOW) { |
6c6be8f1 | 1115 | pwarn("DIRECTORY %D CORRUPTED", dirp->number); |
cf8ac751 | 1116 | dirp->fix = NOFIX; |
690f77ba | 1117 | if (preen) { |
754cadb5 | 1118 | printf(" (SALVAGED)\n"); |
cf8ac751 | 1119 | dirp->fix = FIX; |
690f77ba | 1120 | } else if (reply("SALVAGE") != 0) |
cf8ac751 | 1121 | dirp->fix = FIX; |
690f77ba | 1122 | } |
cf8ac751 | 1123 | if (dirp->fix != FIX) |
24a31719 | 1124 | continue; |
690f77ba KM |
1125 | dp->d_reclen = DIRBLKSIZ; |
1126 | dp->d_ino = 0; | |
1127 | dp->d_namlen = 0; | |
1128 | dirty(&fileblk); | |
1129 | } | |
1130 | if (filsize <= 0 || dirp->loc >= dirp->blksiz) | |
1131 | return NULL; | |
1132 | dp = (DIRECT *)(dirblk.b_buf + dirp->loc); | |
1133 | dirp->loc += dp->d_reclen; | |
1134 | filsize -= dp->d_reclen; | |
1135 | ndp = (DIRECT *)(dirblk.b_buf + dirp->loc); | |
0b2a25e4 KM |
1136 | if ((filsize <= 0 && dirp->loc % DIRBLKSIZ != 0) || |
1137 | (dirp->loc < dirp->blksiz && filsize > 0 && | |
690f77ba KM |
1138 | (ndp->d_ino >= imax || |
1139 | ndp->d_namlen > MAXNAMLEN || ndp->d_namlen < 0 || | |
1140 | ndp->d_reclen <= 0 || | |
0b2a25e4 | 1141 | ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ)))) { |
690f77ba KM |
1142 | size = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ); |
1143 | dirp->loc += size; | |
1144 | filsize -= size; | |
cf8ac751 | 1145 | if (dirp->fix == DONTKNOW) { |
690f77ba | 1146 | pwarn("DIRECTORY %D CORRUPTED", dirp->number); |
cf8ac751 | 1147 | dirp->fix = NOFIX; |
690f77ba KM |
1148 | if (preen) { |
1149 | printf(" (SALVAGED)\n"); | |
cf8ac751 | 1150 | dirp->fix = FIX; |
690f77ba | 1151 | } else if (reply("SALVAGE") != 0) |
cf8ac751 | 1152 | dirp->fix = FIX; |
690f77ba | 1153 | } |
cf8ac751 | 1154 | if (dirp->fix == FIX) { |
690f77ba KM |
1155 | dp->d_reclen += size; |
1156 | dirty(&fileblk); | |
754cadb5 | 1157 | } |
24a31719 | 1158 | } |
690f77ba | 1159 | return (dp); |
24a31719 KM |
1160 | } |
1161 | ||
6e884967 | 1162 | direrr(s) |
8ebf61ca | 1163 | char *s; |
6e884967 KM |
1164 | { |
1165 | register DINODE *dp; | |
1166 | ||
1167 | pwarn("%s ", s); | |
1168 | pinode(); | |
1169 | printf("\n"); | |
1170 | if ((dp = ginode()) != NULL && ftypeok(dp)) | |
24a31719 | 1171 | pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname); |
6e884967 KM |
1172 | else |
1173 | pfatal("NAME=%s", pathname); | |
1174 | return (reply("REMOVE")); | |
1175 | } | |
1176 | ||
1177 | adjust(lcnt) | |
f3c028b7 | 1178 | register short lcnt; |
6e884967 KM |
1179 | { |
1180 | register DINODE *dp; | |
1181 | ||
1182 | if ((dp = ginode()) == NULL) | |
1183 | return; | |
1184 | if (dp->di_nlink == lcnt) { | |
1185 | if (linkup() == 0) | |
1186 | clri("UNREF", 0); | |
1187 | } | |
1188 | else { | |
1189 | pwarn("LINK COUNT %s", | |
24a31719 | 1190 | (lfdir==inum)?lfname:(DIRCT?"DIR":"FILE")); |
6e884967 KM |
1191 | pinode(); |
1192 | printf(" COUNT %d SHOULD BE %d", | |
1193 | dp->di_nlink, dp->di_nlink-lcnt); | |
1194 | if (preen) { | |
1195 | if (lcnt < 0) { | |
1196 | printf("\n"); | |
1197 | preendie(); | |
1198 | } | |
1199 | printf(" (ADJUSTED)\n"); | |
1200 | } | |
1201 | if (preen || reply("ADJUST") == 1) { | |
1202 | dp->di_nlink -= lcnt; | |
1203 | inodirty(); | |
1204 | } | |
1205 | } | |
1206 | } | |
1207 | ||
1208 | clri(s, flg) | |
8ebf61ca | 1209 | char *s; |
6e884967 KM |
1210 | { |
1211 | register DINODE *dp; | |
1212 | ||
1213 | if ((dp = ginode()) == NULL) | |
1214 | return; | |
1215 | if (flg == 1) { | |
24a31719 | 1216 | pwarn("%s %s", s, DIRCT?"DIR":"FILE"); |
6e884967 KM |
1217 | pinode(); |
1218 | } | |
1219 | if (preen || reply("CLEAR") == 1) { | |
1220 | if (preen) | |
1221 | printf(" (CLEARED)\n"); | |
1222 | n_files--; | |
d2c95d76 | 1223 | pfunc = pass4check; |
6e884967 KM |
1224 | ckinode(dp, ADDR); |
1225 | zapino(dp); | |
f5262822 | 1226 | statemap[inum] = USTATE; |
6e884967 KM |
1227 | inodirty(); |
1228 | inosumbad++; | |
1229 | } | |
1230 | } | |
1231 | ||
1232 | setup(dev) | |
8ebf61ca | 1233 | char *dev; |
6e884967 KM |
1234 | { |
1235 | dev_t rootdev; | |
4d308541 | 1236 | struct stat statb; |
6e884967 | 1237 | int super = bflag ? bflag : SBLOCK; |
bf541624 KM |
1238 | int i, j, size; |
1239 | int c, d, cgd; | |
6e884967 KM |
1240 | |
1241 | bflag = 0; | |
1242 | if (stat("/", &statb) < 0) | |
1243 | errexit("Can't stat root\n"); | |
1244 | rootdev = statb.st_dev; | |
1245 | if (stat(dev, &statb) < 0) { | |
1246 | error("Can't stat %s\n", dev); | |
1247 | return (0); | |
1248 | } | |
1249 | rawflg = 0; | |
1250 | if ((statb.st_mode & S_IFMT) == S_IFBLK) | |
1251 | ; | |
1252 | else if ((statb.st_mode & S_IFMT) == S_IFCHR) | |
1253 | rawflg++; | |
1254 | else { | |
1255 | if (reply("file is not a block or character device; OK") == 0) | |
1256 | return (0); | |
1257 | } | |
1258 | if (rootdev == statb.st_rdev) | |
1259 | hotroot++; | |
1260 | if ((dfile.rfdes = open(dev, 0)) < 0) { | |
1261 | error("Can't open %s\n", dev); | |
1262 | return (0); | |
1263 | } | |
1264 | if (preen == 0) | |
1265 | printf("** %s", dev); | |
1266 | if (nflag || (dfile.wfdes = open(dev, 1)) < 0) { | |
1267 | dfile.wfdes = -1; | |
1268 | if (preen) | |
1269 | pfatal("NO WRITE ACCESS"); | |
1270 | printf(" (NO WRITE)"); | |
1271 | } | |
1272 | if (preen == 0) | |
1273 | printf("\n"); | |
184d432f | 1274 | fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; sbsumbad = 0; |
6e884967 KM |
1275 | dfile.mod = 0; |
1276 | n_files = n_blks = n_ffree = n_bfree = 0; | |
1277 | muldup = enddup = &duplist[0]; | |
1278 | badlnp = &badlncnt[0]; | |
1279 | lfdir = 0; | |
1280 | rplyflag = 0; | |
1281 | initbarea(&sblk); | |
1282 | initbarea(&fileblk); | |
1283 | initbarea(&inoblk); | |
1284 | initbarea(&cgblk); | |
184d432f KM |
1285 | /* |
1286 | * Read in the super block and its summary info. | |
1287 | */ | |
c312eebd | 1288 | if (bread(&dfile, &sblock, super, SBSIZE) == 0) |
6e884967 | 1289 | return (0); |
f3c028b7 | 1290 | sblk.b_bno = super; |
c312eebd | 1291 | sblk.b_size = SBSIZE; |
aca50d72 KM |
1292 | /* |
1293 | * run a few consistency checks of the super block | |
1294 | */ | |
6e884967 KM |
1295 | if (sblock.fs_magic != FS_MAGIC) |
1296 | { badsb("MAGIC NUMBER WRONG"); return (0); } | |
1297 | if (sblock.fs_ncg < 1) | |
1298 | { badsb("NCG OUT OF RANGE"); return (0); } | |
1299 | if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) | |
1300 | { badsb("CPG OUT OF RANGE"); return (0); } | |
1301 | if (sblock.fs_nsect < 1) | |
1302 | { badsb("NSECT < 1"); return (0); } | |
1303 | if (sblock.fs_ntrak < 1) | |
1304 | { badsb("NTRAK < 1"); return (0); } | |
aca50d72 KM |
1305 | if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak) |
1306 | { badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); } | |
1307 | if (sblock.fs_ipg % INOPB(&sblock)) | |
1308 | { badsb("INODES NOT MULTIPLE OF A BLOCK"); return (0); } | |
6994bf5d | 1309 | if (cgdmin(&sblock, 0) >= sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock)) |
6e884967 | 1310 | { badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); return (0); } |
aca50d72 KM |
1311 | if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl || |
1312 | (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) | |
6e884967 | 1313 | { badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); } |
b6407c9d | 1314 | if (sblock.fs_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock)) |
6e884967 | 1315 | { badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); } |
aca50d72 KM |
1316 | if (sblock.fs_size * NSPF(&sblock) <= |
1317 | (sblock.fs_ncyl - 1) * sblock.fs_spc) | |
6e884967 | 1318 | { badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); } |
aca50d72 | 1319 | if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) |
6e884967 KM |
1320 | { badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); } |
1321 | /* rest we COULD repair... */ | |
3352e84a KM |
1322 | if (sblock.fs_cgsize != fragroundup(&sblock, |
1323 | sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY))) | |
6e884967 | 1324 | { badsb("CGSIZE INCORRECT"); return (0); } |
bf541624 KM |
1325 | if (sblock.fs_cssize != |
1326 | fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum))) | |
6e884967 KM |
1327 | { badsb("CSSIZE INCORRECT"); return (0); } |
1328 | fmax = sblock.fs_size; | |
1329 | imax = sblock.fs_ncg * sblock.fs_ipg; | |
bf541624 KM |
1330 | n_bad = cgsblock(&sblock, 0); /* boot block plus dedicated sblock */ |
1331 | /* | |
1332 | * read in the summary info. | |
1333 | */ | |
1334 | for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { | |
1335 | size = sblock.fs_cssize - i < sblock.fs_bsize ? | |
1336 | sblock.fs_cssize - i : sblock.fs_bsize; | |
1337 | sblock.fs_csp[j] = (struct csum *)calloc(1, size); | |
1338 | bread(&dfile, (char *)sblock.fs_csp[j], | |
1339 | fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), | |
1340 | size); | |
1341 | } | |
aca50d72 | 1342 | /* |
bf541624 | 1343 | * allocate and initialize the necessary maps |
aca50d72 | 1344 | */ |
6e884967 | 1345 | bmapsz = roundup(howmany(fmax, NBBY), sizeof(short)); |
79f5f76a | 1346 | blockmap = (char *)calloc(bmapsz, sizeof (char)); |
f3385032 KM |
1347 | if (blockmap == NULL) { |
1348 | printf("cannot alloc %d bytes for blockmap\n", bmapsz); | |
1349 | exit(1); | |
1350 | } | |
6e884967 | 1351 | freemap = (char *)calloc(bmapsz, sizeof (char)); |
f3385032 KM |
1352 | if (freemap == NULL) { |
1353 | printf("cannot alloc %d bytes for freemap\n", bmapsz); | |
1354 | exit(1); | |
1355 | } | |
6e884967 | 1356 | statemap = (char *)calloc(imax+1, sizeof(char)); |
f3385032 KM |
1357 | if (statemap == NULL) { |
1358 | printf("cannot alloc %d bytes for statemap\n", imax + 1); | |
1359 | exit(1); | |
1360 | } | |
6e884967 | 1361 | lncntp = (short *)calloc(imax+1, sizeof(short)); |
f3385032 KM |
1362 | if (lncntp == NULL) { |
1363 | printf("cannot alloc %d bytes for lncntp\n", | |
1364 | (imax + 1) * sizeof(short)); | |
1365 | exit(1); | |
1366 | } | |
bf541624 KM |
1367 | for (c = 0; c < sblock.fs_ncg; c++) { |
1368 | cgd = cgdmin(&sblock, c); | |
1369 | if (c == 0) { | |
1370 | d = cgbase(&sblock, c); | |
1371 | cgd += howmany(sblock.fs_cssize, sblock.fs_fsize); | |
1372 | } else | |
1373 | d = cgsblock(&sblock, c); | |
1374 | for (; d < cgd; d++) | |
1375 | setbmap(d); | |
1376 | } | |
6e884967 | 1377 | |
f3c028b7 | 1378 | startinum = imax + 1; |
6e884967 KM |
1379 | return (1); |
1380 | ||
1381 | badsb: | |
1382 | ckfini(); | |
1383 | return (0); | |
1384 | } | |
1385 | ||
1386 | badsb(s) | |
1387 | char *s; | |
1388 | { | |
1389 | ||
1390 | if (preen) | |
1391 | printf("%s: ", devname); | |
1392 | printf("BAD SUPER BLOCK: %s\n", s); | |
1393 | pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n"); | |
1394 | pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n"); | |
1395 | } | |
1396 | ||
1397 | DINODE * | |
1398 | ginode() | |
1399 | { | |
1400 | daddr_t iblk; | |
1401 | ||
f3385032 KM |
1402 | if (inum < ROOTINO || inum > imax) { |
1403 | if (debug && (inum < 0 || inum > imax)) | |
1404 | printf("inum out of range (%d)\n", inum); | |
6e884967 | 1405 | return (NULL); |
f3385032 | 1406 | } |
b6407c9d | 1407 | if (inum < startinum || inum >= startinum + INOPB(&sblock)) { |
6994bf5d | 1408 | iblk = itod(&sblock, inum); |
b6407c9d | 1409 | if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) { |
6e884967 KM |
1410 | return (NULL); |
1411 | } | |
b6407c9d | 1412 | startinum = (inum / INOPB(&sblock)) * INOPB(&sblock); |
6e884967 | 1413 | } |
b6407c9d | 1414 | return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]); |
6e884967 KM |
1415 | } |
1416 | ||
1417 | ftypeok(dp) | |
1418 | DINODE *dp; | |
1419 | { | |
1420 | switch (dp->di_mode & IFMT) { | |
1421 | ||
1422 | case IFDIR: | |
1423 | case IFREG: | |
1424 | case IFBLK: | |
1425 | case IFCHR: | |
ea47352d | 1426 | case IFLNK: |
6e884967 KM |
1427 | return (1); |
1428 | ||
1429 | default: | |
1430 | return (0); | |
1431 | } | |
1432 | } | |
1433 | ||
1434 | reply(s) | |
1435 | char *s; | |
1436 | { | |
1437 | char line[80]; | |
1438 | ||
1439 | if (preen) | |
1440 | pfatal("INTERNAL ERROR: GOT TO reply()"); | |
1441 | rplyflag = 1; | |
1442 | printf("\n%s? ", s); | |
1443 | if (nflag || dfile.wfdes < 0) { | |
1444 | printf(" no\n\n"); | |
1445 | return (0); | |
1446 | } | |
1447 | if (yflag) { | |
1448 | printf(" yes\n\n"); | |
1449 | return (1); | |
1450 | } | |
1451 | if (getline(stdin, line, sizeof(line)) == EOF) | |
1452 | errexit("\n"); | |
1453 | printf("\n"); | |
1454 | if (line[0] == 'y' || line[0] == 'Y') | |
1455 | return (1); | |
1456 | else | |
1457 | return (0); | |
1458 | } | |
1459 | ||
1460 | getline(fp, loc, maxlen) | |
1461 | FILE *fp; | |
1462 | char *loc; | |
1463 | { | |
1464 | register n; | |
1465 | register char *p, *lastloc; | |
1466 | ||
1467 | p = loc; | |
1468 | lastloc = &p[maxlen-1]; | |
1469 | while ((n = getc(fp)) != '\n') { | |
1470 | if (n == EOF) | |
1471 | return (EOF); | |
1472 | if (!isspace(n) && p < lastloc) | |
1473 | *p++ = n; | |
1474 | } | |
1475 | *p = 0; | |
1476 | return (p - loc); | |
1477 | } | |
1478 | ||
1479 | BUFAREA * | |
1480 | getblk(bp, blk, size) | |
1481 | daddr_t blk; | |
1482 | register BUFAREA *bp; | |
1483 | int size; | |
1484 | { | |
1485 | register struct filecntl *fcp; | |
b6407c9d | 1486 | daddr_t dblk; |
6e884967 KM |
1487 | |
1488 | fcp = &dfile; | |
b6407c9d KM |
1489 | dblk = fsbtodb(&sblock, blk); |
1490 | if (bp->b_bno == dblk) | |
6e884967 KM |
1491 | return (bp); |
1492 | flush(fcp, bp); | |
b6407c9d KM |
1493 | if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) { |
1494 | bp->b_bno = dblk; | |
6e884967 KM |
1495 | bp->b_size = size; |
1496 | return (bp); | |
1497 | } | |
1498 | bp->b_bno = (daddr_t)-1; | |
1499 | return (NULL); | |
1500 | } | |
1501 | ||
1502 | flush(fcp, bp) | |
1503 | struct filecntl *fcp; | |
1504 | register BUFAREA *bp; | |
1505 | { | |
1506 | ||
1507 | if (bp->b_dirty) | |
1508 | bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size); | |
1509 | bp->b_dirty = 0; | |
1510 | } | |
1511 | ||
1512 | rwerr(s, blk) | |
1513 | char *s; | |
1514 | daddr_t blk; | |
1515 | { | |
1516 | ||
1517 | if (preen == 0) | |
1518 | printf("\n"); | |
1519 | pfatal("CANNOT %s: BLK %ld", s, blk); | |
1520 | if (reply("CONTINUE") == 0) | |
1521 | errexit("Program terminated\n"); | |
1522 | } | |
1523 | ||
1524 | ckfini() | |
1525 | { | |
1526 | ||
1527 | flush(&dfile, &fileblk); | |
1528 | flush(&dfile, &sblk); | |
f3c028b7 KM |
1529 | if (sblk.b_bno != SBLOCK) { |
1530 | sblk.b_bno = SBLOCK; | |
1531 | sbdirty(); | |
1532 | flush(&dfile, &sblk); | |
1533 | } | |
6e884967 KM |
1534 | flush(&dfile, &inoblk); |
1535 | close(dfile.rfdes); | |
1536 | close(dfile.wfdes); | |
1537 | } | |
1538 | ||
1539 | pinode() | |
1540 | { | |
1541 | register DINODE *dp; | |
1542 | register char *p; | |
24a31719 | 1543 | char uidbuf[BUFSIZ]; |
6e884967 KM |
1544 | char *ctime(); |
1545 | ||
1546 | printf(" I=%u ", inum); | |
1547 | if ((dp = ginode()) == NULL) | |
1548 | return; | |
1549 | printf(" OWNER="); | |
1550 | if (getpw((int)dp->di_uid, uidbuf) == 0) { | |
1551 | for (p = uidbuf; *p != ':'; p++); | |
1552 | *p = 0; | |
1553 | printf("%s ", uidbuf); | |
1554 | } | |
1555 | else { | |
1556 | printf("%d ", dp->di_uid); | |
1557 | } | |
1558 | printf("MODE=%o\n", dp->di_mode); | |
1559 | if (preen) | |
1560 | printf("%s: ", devname); | |
1561 | printf("SIZE=%ld ", dp->di_size); | |
1562 | p = ctime(&dp->di_mtime); | |
1563 | printf("MTIME=%12.12s %4.4s ", p+4, p+20); | |
1564 | } | |
1565 | ||
6e884967 KM |
1566 | makecg() |
1567 | { | |
f3c028b7 | 1568 | int c, blk; |
bf541624 | 1569 | daddr_t dbase, d, dlower, dupper, dmax; |
6e884967 KM |
1570 | long i, j, s; |
1571 | register struct csum *cs; | |
f3c028b7 | 1572 | register DINODE *dp; |
6e884967 | 1573 | |
0947395d KM |
1574 | sblock.fs_cstotal.cs_nbfree = 0; |
1575 | sblock.fs_cstotal.cs_nffree = 0; | |
1576 | sblock.fs_cstotal.cs_nifree = 0; | |
1577 | sblock.fs_cstotal.cs_ndir = 0; | |
6e884967 | 1578 | for (c = 0; c < sblock.fs_ncg; c++) { |
6994bf5d | 1579 | dbase = cgbase(&sblock, c); |
6e884967 | 1580 | dmax = dbase + sblock.fs_fpg; |
8f99f49c | 1581 | if (dmax > sblock.fs_size) { |
bf4c734c | 1582 | for ( ; dmax >= sblock.fs_size; dmax--) |
2e9860b5 | 1583 | clrbit(cgrp.cg_free, dmax - dbase); |
8f99f49c KM |
1584 | dmax++; |
1585 | } | |
bf541624 KM |
1586 | dlower = cgsblock(&sblock, c) - dbase; |
1587 | dupper = cgdmin(&sblock, c) - dbase; | |
b6407c9d | 1588 | cs = &sblock.fs_cs(&sblock, c); |
6e884967 KM |
1589 | cgrp.cg_time = time(0); |
1590 | cgrp.cg_magic = CG_MAGIC; | |
1591 | cgrp.cg_cgx = c; | |
1592 | cgrp.cg_ncyl = sblock.fs_cpg; | |
1593 | cgrp.cg_niblk = sblock.fs_ipg; | |
1594 | cgrp.cg_ndblk = dmax - dbase; | |
0947395d KM |
1595 | cgrp.cg_cs.cs_ndir = 0; |
1596 | cgrp.cg_cs.cs_nffree = 0; | |
1597 | cgrp.cg_cs.cs_nbfree = 0; | |
1598 | cgrp.cg_cs.cs_nifree = 0; | |
bf541624 KM |
1599 | cgrp.cg_rotor = 0; |
1600 | cgrp.cg_frotor = 0; | |
92ea6158 | 1601 | cgrp.cg_irotor = 0; |
b6407c9d | 1602 | for (i = 0; i < sblock.fs_frag; i++) |
f3c028b7 | 1603 | cgrp.cg_frsum[i] = 0; |
6e884967 | 1604 | inum = sblock.fs_ipg * c; |
f3c028b7 | 1605 | for (i = 0; i < sblock.fs_ipg; inum++, i++) { |
bf4c734c KM |
1606 | cgrp.cg_cs.cs_nifree++; |
1607 | clrbit(cgrp.cg_iused, i); | |
f3c028b7 KM |
1608 | dp = ginode(); |
1609 | if (dp == NULL) | |
1610 | continue; | |
1611 | if (ALLOC) { | |
24a31719 | 1612 | if (DIRCT) |
0947395d | 1613 | cgrp.cg_cs.cs_ndir++; |
bf4c734c | 1614 | cgrp.cg_cs.cs_nifree--; |
f3c028b7 KM |
1615 | setbit(cgrp.cg_iused, i); |
1616 | continue; | |
1617 | } | |
6e884967 KM |
1618 | } |
1619 | while (i < MAXIPG) { | |
1620 | clrbit(cgrp.cg_iused, i); | |
1621 | i++; | |
1622 | } | |
bf4c734c KM |
1623 | if (c == 0) |
1624 | for (i = 0; i < ROOTINO; i++) { | |
1625 | setbit(cgrp.cg_iused, i); | |
1626 | cgrp.cg_cs.cs_nifree--; | |
1627 | } | |
43f6367c KM |
1628 | for (s = 0; s < MAXCPG; s++) { |
1629 | cgrp.cg_btot[s] = 0; | |
6e884967 KM |
1630 | for (i = 0; i < NRPOS; i++) |
1631 | cgrp.cg_b[s][i] = 0; | |
43f6367c | 1632 | } |
6e884967 | 1633 | if (c == 0) { |
bf541624 | 1634 | dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); |
6e884967 | 1635 | } |
bf541624 | 1636 | for (d = dlower; d < dupper; d++) |
6e884967 | 1637 | clrbit(cgrp.cg_free, d); |
bf541624 KM |
1638 | for (d = 0; (d + sblock.fs_frag) <= dmax - dbase; |
1639 | d += sblock.fs_frag) { | |
6e884967 | 1640 | j = 0; |
b6407c9d | 1641 | for (i = 0; i < sblock.fs_frag; i++) { |
bf541624 KM |
1642 | if (!getbmap(dbase + d + i)) { |
1643 | setbit(cgrp.cg_free, d + i); | |
6e884967 KM |
1644 | j++; |
1645 | } else | |
1646 | clrbit(cgrp.cg_free, d+i); | |
1647 | } | |
b6407c9d | 1648 | if (j == sblock.fs_frag) { |
0947395d | 1649 | cgrp.cg_cs.cs_nbfree++; |
43f6367c | 1650 | cgrp.cg_btot[cbtocylno(&sblock, d)]++; |
aca50d72 KM |
1651 | cgrp.cg_b[cbtocylno(&sblock, d)] |
1652 | [cbtorpos(&sblock, d)]++; | |
f3c028b7 | 1653 | } else if (j > 0) { |
0947395d | 1654 | cgrp.cg_cs.cs_nffree += j; |
bf541624 | 1655 | blk = blkmap(&sblock, cgrp.cg_free, d); |
b6407c9d | 1656 | fragacct(&sblock, blk, cgrp.cg_frsum, 1); |
f3c028b7 | 1657 | } |
6e884967 | 1658 | } |
f3c028b7 | 1659 | for (j = d; d < dmax - dbase; d++) { |
bf541624 | 1660 | if (!getbmap(dbase + d)) { |
6e884967 | 1661 | setbit(cgrp.cg_free, d); |
0947395d | 1662 | cgrp.cg_cs.cs_nffree++; |
6e884967 KM |
1663 | } else |
1664 | clrbit(cgrp.cg_free, d); | |
1665 | } | |
f3c028b7 | 1666 | if (j != d) { |
bf541624 | 1667 | blk = blkmap(&sblock, cgrp.cg_free, j); |
b6407c9d | 1668 | fragacct(&sblock, blk, cgrp.cg_frsum, 1); |
f3c028b7 | 1669 | } |
b6407c9d | 1670 | for (; d < MAXBPG(&sblock); d++) |
6e884967 | 1671 | clrbit(cgrp.cg_free, d); |
0947395d KM |
1672 | sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree; |
1673 | sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree; | |
1674 | sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree; | |
1675 | sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir; | |
1676 | *cs = cgrp.cg_cs; | |
6994bf5d | 1677 | bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)), |
3352e84a | 1678 | sblock.fs_cgsize); |
6e884967 | 1679 | } |
bf541624 KM |
1680 | for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { |
1681 | bwrite(&dfile, (char *)sblock.fs_csp[j], | |
1682 | fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), | |
1683 | sblock.fs_cssize - i < sblock.fs_bsize ? | |
1684 | sblock.fs_cssize - i : sblock.fs_bsize); | |
c2a050cf | 1685 | } |
6e884967 KM |
1686 | sblock.fs_ronly = 0; |
1687 | sblock.fs_fmod = 0; | |
1688 | sbdirty(); | |
1689 | } | |
1690 | ||
f3c028b7 KM |
1691 | /* |
1692 | * update the frsum fields to reflect addition or deletion | |
1693 | * of some frags | |
1694 | */ | |
b6407c9d KM |
1695 | fragacct(fs, fragmap, fraglist, cnt) |
1696 | struct fs *fs; | |
1b940b13 | 1697 | int fragmap; |
0947395d | 1698 | long fraglist[]; |
f3c028b7 KM |
1699 | int cnt; |
1700 | { | |
1701 | int inblk; | |
1702 | register int field, subfield; | |
1703 | register int siz, pos; | |
1704 | ||
b6407c9d | 1705 | inblk = (int)(fragtbl[fs->fs_frag][fragmap] << 1); |
f3c028b7 | 1706 | fragmap <<= 1; |
b6407c9d | 1707 | for (siz = 1; siz < fs->fs_frag; siz++) { |
156b8f82 | 1708 | if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) |
f3c028b7 KM |
1709 | continue; |
1710 | field = around[siz]; | |
1711 | subfield = inside[siz]; | |
b6407c9d | 1712 | for (pos = siz; pos <= fs->fs_frag; pos++) { |
f3c028b7 KM |
1713 | if ((fragmap & field) == subfield) { |
1714 | fraglist[siz] += cnt; | |
1715 | pos += siz; | |
1716 | field <<= siz; | |
1717 | subfield <<= siz; | |
1718 | } | |
1719 | field <<= 1; | |
1720 | subfield <<= 1; | |
1721 | } | |
1722 | } | |
1723 | } | |
1724 | ||
6e884967 KM |
1725 | findino(dirp) |
1726 | register DIRECT *dirp; | |
1727 | { | |
6e884967 KM |
1728 | if (dirp->d_ino == 0) |
1729 | return (KEEPON); | |
24a31719 KM |
1730 | if (!strcmp(dirp->d_name, srchname)) { |
1731 | if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax) | |
1732 | parentdir = dirp->d_ino; | |
1733 | return (STOP); | |
6e884967 KM |
1734 | } |
1735 | return (KEEPON); | |
1736 | } | |
1737 | ||
1738 | mkentry(dirp) | |
1739 | register DIRECT *dirp; | |
1740 | { | |
1741 | register ino_t in; | |
1742 | register char *p; | |
754cadb5 KM |
1743 | DIRECT newent; |
1744 | int newlen, oldlen; | |
6e884967 | 1745 | |
754cadb5 KM |
1746 | newent.d_namlen = 11; |
1747 | newlen = DIRSIZ(&newent); | |
1748 | if (dirp->d_ino != 0) | |
1749 | oldlen = DIRSIZ(dirp); | |
1750 | else | |
1751 | oldlen = 0; | |
1752 | if (dirp->d_reclen - oldlen < newlen) | |
6e884967 | 1753 | return (KEEPON); |
754cadb5 KM |
1754 | newent.d_reclen = dirp->d_reclen - oldlen; |
1755 | dirp->d_reclen = oldlen; | |
1756 | dirp = (struct direct *)(((char *)dirp) + oldlen); | |
6e884967 | 1757 | dirp->d_ino = orphan; |
754cadb5 KM |
1758 | dirp->d_reclen = newent.d_reclen; |
1759 | p = &dirp->d_name[2]; | |
1760 | for (in = imax; in > 0; in /= 10) | |
1761 | p++; | |
6e884967 | 1762 | *--p = 0; |
754cadb5 KM |
1763 | dirp->d_namlen = p - dirp->d_name; |
1764 | in = orphan; | |
6e884967 KM |
1765 | while (p > dirp->d_name) { |
1766 | *--p = (in % 10) + '0'; | |
1767 | in /= 10; | |
1768 | } | |
1769 | *p = '#'; | |
1770 | return (ALTERD|STOP); | |
1771 | } | |
1772 | ||
1773 | chgdd(dirp) | |
1774 | register DIRECT *dirp; | |
1775 | { | |
1776 | if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' && | |
1777 | dirp->d_name[2] == 0) { | |
1778 | dirp->d_ino = lfdir; | |
1779 | return (ALTERD|STOP); | |
1780 | } | |
1781 | return (KEEPON); | |
1782 | } | |
1783 | ||
1784 | linkup() | |
1785 | { | |
1786 | register DINODE *dp; | |
1787 | register lostdir; | |
1788 | register ino_t pdir; | |
1789 | ||
1790 | if ((dp = ginode()) == NULL) | |
1791 | return (0); | |
24a31719 | 1792 | lostdir = DIRCT; |
6e884967 KM |
1793 | pdir = parentdir; |
1794 | pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); | |
1795 | pinode(); | |
1796 | if (preen && dp->di_size == 0) | |
1797 | return (0); | |
1798 | if (preen) | |
1799 | printf(" (RECONNECTED)\n"); | |
1800 | else | |
1801 | if (reply("RECONNECT") == 0) | |
1802 | return (0); | |
1803 | orphan = inum; | |
1804 | if (lfdir == 0) { | |
1805 | inum = ROOTINO; | |
1806 | if ((dp = ginode()) == NULL) { | |
1807 | inum = orphan; | |
1808 | return (0); | |
1809 | } | |
1810 | pfunc = findino; | |
1811 | srchname = lfname; | |
1812 | filsize = dp->di_size; | |
1813 | parentdir = 0; | |
1814 | ckinode(dp, DATA); | |
1815 | inum = orphan; | |
1816 | if ((lfdir = parentdir) == 0) { | |
1817 | pfatal("SORRY. NO lost+found DIRECTORY"); | |
1818 | printf("\n\n"); | |
1819 | return (0); | |
1820 | } | |
1821 | } | |
1822 | inum = lfdir; | |
f5262822 | 1823 | if ((dp = ginode()) == NULL || !DIRCT || statemap[inum] != FSTATE) { |
6e884967 KM |
1824 | inum = orphan; |
1825 | pfatal("SORRY. NO lost+found DIRECTORY"); | |
1826 | printf("\n\n"); | |
1827 | return (0); | |
1828 | } | |
3352e84a KM |
1829 | if (fragoff(&sblock, dp->di_size)) { |
1830 | dp->di_size = fragroundup(&sblock, dp->di_size); | |
6e884967 KM |
1831 | inodirty(); |
1832 | } | |
1833 | filsize = dp->di_size; | |
1834 | inum = orphan; | |
1835 | pfunc = mkentry; | |
1836 | if ((ckinode(dp, DATA) & ALTERD) == 0) { | |
1837 | pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); | |
1838 | printf("\n\n"); | |
1839 | return (0); | |
1840 | } | |
f5262822 | 1841 | lncntp[inum]--; |
6e884967 KM |
1842 | if (lostdir) { |
1843 | pfunc = chgdd; | |
1844 | dp = ginode(); | |
1845 | filsize = dp->di_size; | |
1846 | ckinode(dp, DATA); | |
1847 | inum = lfdir; | |
1848 | if ((dp = ginode()) != NULL) { | |
1849 | dp->di_nlink++; | |
1850 | inodirty(); | |
f5262822 | 1851 | lncntp[inum]++; |
6e884967 KM |
1852 | } |
1853 | inum = orphan; | |
1854 | pwarn("DIR I=%u CONNECTED. ", orphan); | |
1855 | printf("PARENT WAS I=%u\n", pdir); | |
1856 | if (preen == 0) | |
1857 | printf("\n"); | |
1858 | } | |
1859 | return (1); | |
1860 | } | |
1861 | ||
1862 | bread(fcp, buf, blk, size) | |
1863 | daddr_t blk; | |
1864 | register struct filecntl *fcp; | |
1865 | register size; | |
1866 | char *buf; | |
1867 | { | |
b6407c9d | 1868 | if (lseek(fcp->rfdes, blk * DEV_BSIZE, 0) < 0) |
6e884967 KM |
1869 | rwerr("SEEK", blk); |
1870 | else if (read(fcp->rfdes, buf, size) == size) | |
1871 | return (1); | |
1872 | rwerr("READ", blk); | |
1873 | return (0); | |
1874 | } | |
1875 | ||
1876 | bwrite(fcp, buf, blk, size) | |
1877 | daddr_t blk; | |
1878 | register struct filecntl *fcp; | |
1879 | register size; | |
1880 | char *buf; | |
1881 | { | |
1882 | ||
1883 | if (fcp->wfdes < 0) | |
1884 | return (0); | |
b6407c9d | 1885 | if (lseek(fcp->wfdes, blk * DEV_BSIZE, 0) < 0) |
6e884967 KM |
1886 | rwerr("SEEK", blk); |
1887 | else if (write(fcp->wfdes, buf, size) == size) { | |
1888 | fcp->mod = 1; | |
1889 | return (1); | |
1890 | } | |
1891 | rwerr("WRITE", blk); | |
1892 | return (0); | |
1893 | } | |
1894 | ||
1895 | catch() | |
1896 | { | |
1897 | ||
1898 | ckfini(); | |
1899 | exit(12); | |
1900 | } | |
b6407c9d KM |
1901 | |
1902 | /* | |
1903 | * block operations | |
1904 | */ | |
1905 | ||
1906 | isblock(fs, cp, h) | |
1907 | struct fs *fs; | |
1908 | unsigned char *cp; | |
1909 | int h; | |
1910 | { | |
1911 | unsigned char mask; | |
1912 | ||
1913 | switch (fs->fs_frag) { | |
1914 | case 8: | |
1915 | return (cp[h] == 0xff); | |
1916 | case 4: | |
1917 | mask = 0x0f << ((h & 0x1) << 2); | |
1918 | return ((cp[h >> 1] & mask) == mask); | |
1919 | case 2: | |
1920 | mask = 0x03 << ((h & 0x3) << 1); | |
1921 | return ((cp[h >> 2] & mask) == mask); | |
1922 | case 1: | |
1923 | mask = 0x01 << (h & 0x7); | |
1924 | return ((cp[h >> 3] & mask) == mask); | |
1925 | default: | |
6994bf5d KM |
1926 | error("isblock bad fs_frag %d\n", fs->fs_frag); |
1927 | return (0); | |
b6407c9d KM |
1928 | } |
1929 | } | |
4d308541 | 1930 | |
d2c95d76 BJ |
1931 | char * |
1932 | unrawname(cp) | |
1933 | char *cp; | |
1934 | { | |
1935 | char *dp = rindex(cp, '/'); | |
1936 | struct stat stb; | |
1937 | ||
1938 | if (dp == 0) | |
1939 | return (cp); | |
1940 | if (stat(cp, &stb) < 0) | |
1941 | return (cp); | |
1942 | if ((stb.st_mode&S_IFMT) != S_IFCHR) | |
1943 | return (cp); | |
1944 | if (*(dp+1) != 'r') | |
1945 | return (cp); | |
1946 | strcpy(dp+1, dp+2); | |
1947 | return (cp); | |
1948 | } | |
1949 | ||
1950 | char * | |
1951 | rawname(cp) | |
1952 | char *cp; | |
1953 | { | |
1954 | static char rawbuf[32]; | |
1955 | char *dp = rindex(cp, '/'); | |
1956 | ||
1957 | if (dp == 0) | |
1958 | return (0); | |
1959 | *dp = 0; | |
1960 | strcpy(rawbuf, cp); | |
1961 | *dp = '/'; | |
1962 | strcat(rawbuf, "/r"); | |
1963 | strcat(rawbuf, dp+1); | |
1964 | return (rawbuf); | |
1965 | } | |
1966 | ||
1967 | /* VARARGS1 */ | |
1968 | error(s1, s2, s3, s4) | |
1969 | char *s1; | |
1970 | { | |
4d308541 | 1971 | |
d2c95d76 BJ |
1972 | printf(s1, s2, s3, s4); |
1973 | } | |
4d308541 | 1974 | |
d2c95d76 BJ |
1975 | /* VARARGS1 */ |
1976 | errexit(s1, s2, s3, s4) | |
1977 | char *s1; | |
1978 | { | |
1979 | error(s1, s2, s3, s4); | |
1980 | exit(8); | |
1981 | } | |
4d308541 KM |
1982 | |
1983 | /* | |
d2c95d76 BJ |
1984 | * An inconsistency occured which shouldn't during normal operations. |
1985 | * Die if preening, otw just printf. | |
4d308541 | 1986 | */ |
d2c95d76 BJ |
1987 | /* VARARGS1 */ |
1988 | pfatal(s, a1, a2, a3) | |
1989 | char *s; | |
1990 | { | |
4d308541 | 1991 | |
d2c95d76 BJ |
1992 | if (preen) { |
1993 | printf("%s: ", devname); | |
1994 | printf(s, a1, a2, a3); | |
1995 | printf("\n"); | |
1996 | preendie(); | |
1997 | } | |
1998 | printf(s, a1, a2, a3); | |
1999 | } | |
4d308541 | 2000 | |
d2c95d76 BJ |
2001 | preendie() |
2002 | { | |
4d308541 | 2003 | |
d2c95d76 BJ |
2004 | printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname); |
2005 | exit(8); | |
2006 | } | |
4d308541 KM |
2007 | |
2008 | /* | |
d2c95d76 BJ |
2009 | * Pwarn is like printf when not preening, |
2010 | * or a warning (preceded by filename) when preening. | |
4d308541 | 2011 | */ |
d2c95d76 BJ |
2012 | /* VARARGS1 */ |
2013 | pwarn(s, a1, a2, a3, a4, a5, a6) | |
2014 | char *s; | |
2015 | { | |
2016 | ||
2017 | if (preen) | |
2018 | printf("%s: ", devname); | |
2019 | printf(s, a1, a2, a3, a4, a5, a6); | |
2020 | } |