pci: don't do sanity check for missing pci bus, the check can misfire.
[minix.git] / commands / simple / fsck.c
blob08916111974807781b03d1d48518a8810bc34e2a
1 /* Hacks for version 1.6 */
3 #define INODES_PER_BLOCK V2_INODES_PER_BLOCK(block_size)
4 #define INODE_SIZE ((int) V2_INODE_SIZE)
5 #define WORDS_PER_BLOCK (block_size / (int) sizeof(bitchunk_t))
6 #define MAX_ZONES (V2_NR_DZONES+V2_INDIRECTS(block_size)+(long)V2_INDIRECTS(block_size)*V2_INDIRECTS(block_size))
7 #define NR_DZONE_NUM V2_NR_DZONES
8 #define NR_INDIRECTS V2_INDIRECTS(block_size)
9 #define NR_ZONE_NUMS V2_NR_TZONES
10 #define ZONE_NUM_SIZE V2_ZONE_NUM_SIZE
11 #define bit_nr bit_t
12 #define block_nr block_t
13 #define d_inode d2_inode
14 #define d_inum d_ino
15 #define dir_struct struct direct
16 #define i_mode d2_mode
17 #define i_nlinks d2_nlinks
18 #define i_size d2_size
19 #define i_zone d2_zone
20 #define zone_nr zone_t
22 /* fsck - file system checker Author: Robbert van Renesse */
24 /* Modified by Norbert Schlenker
25 * Removed vestiges of standalone/DOS versions:
26 * - various unused variables and buffers removed
27 * - now uses library functions rather than private internal routines
28 * - bytewise structure copies replaced by structure assignment
29 * - fixed one bug with 14 character file names
30 * - other small tweaks for speed
32 * Modified by Lars Fredriksen at the request of Andy Tanenbaum, 90-03-10.
33 * Removed -m option, by which fsck could be told to make a file
34 * system on a 360K floppy. The code had limited utility, was buggy,
35 * and failed due to a bug in the ACK C compiler. Use mkfs instead!
38 #include <sys/types.h>
39 #include <sys/dir.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <limits.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <minix/config.h>
48 #include <minix/const.h>
49 #include <minix/type.h>
50 #include <minix/u64.h>
51 #include "../../servers/mfs/const.h"
52 #include "../../servers/mfs/inode.h"
53 #include "../../servers/mfs/type.h"
54 #include <minix/fslib.h>
55 #include <stdio.h>
56 #include <sys/stat.h>
57 #include <a.out.h>
58 #include <tools.h>
59 #include <dirent.h>
61 #undef N_DATA
63 unsigned int fs_version = 2, block_size = 0;
65 #define BITSHIFT 4 /* = log2(#bits(int)) */
67 #define MAXPRINT 80 /* max. number of error lines in chkmap */
68 #define CINDIR 128 /* number of indirect zno's read at a time */
69 #define CDIRECT 1 /* number of dir entries read at a time */
71 /* Macros for handling bitmaps. Now bit_t is long, these are bulky and the
72 * type demotions produce a lot of lint. The explicit demotion in POWEROFBIT
73 * is for efficiency and assumes 2's complement ints. Lint should be clever
74 * enough not to warn about it since BITMASK is small, but isn't. (It would
75 * be easier to get right if bit_t was was unsigned (long) since then there
76 * would be no danger from wierd sign representations. Lint doesn't know
77 * we only use non-negative bit numbers.) There will usually be an implicit
78 * demotion when WORDOFBIT is used as an array index. This should be safe
79 * since memory for bitmaps will run out first.
81 #define BITMASK ((1 << BITSHIFT) - 1)
82 #define WORDOFBIT(b) ((b) >> BITSHIFT)
83 #define POWEROFBIT(b) (1 << ((int) (b) & BITMASK))
84 #define setbit(w, b) (w[WORDOFBIT(b)] |= POWEROFBIT(b))
85 #define clrbit(w, b) (w[WORDOFBIT(b)] &= ~POWEROFBIT(b))
86 #define bitset(w, b) (w[WORDOFBIT(b)] & POWEROFBIT(b))
88 #define ZONE_CT 360 /* default zones (when making file system) */
89 #define INODE_CT 95 /* default inodes (when making file system) */
91 #include "../../servers/mfs/super.h"
92 static struct super_block sb;
94 #define STICKY_BIT 01000 /* not defined anywhere else */
96 /* Ztob gives the block address of a zone
97 * btoa64 gives the byte address of a block
99 #define ztob(z) ((block_nr) (z) << sb.s_log_zone_size)
100 #define btoa64(b) (mul64u(b, block_size))
101 #define SCALE ((int) ztob(1)) /* # blocks in a zone */
102 #define FIRST ((zone_nr) sb.s_firstdatazone) /* as the name says */
104 /* # blocks of each type */
105 #define N_IMAP (sb.s_imap_blocks)
106 #define N_ZMAP (sb.s_zmap_blocks)
107 #define N_ILIST ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
108 #define N_DATA (sb.s_zones - FIRST)
110 /* Block address of each type */
111 #define OFFSET_SUPER_BLOCK SUPER_BLOCK_BYTES
112 #define BLK_IMAP 2
113 #define BLK_ZMAP (BLK_IMAP + N_IMAP)
114 #define BLK_ILIST (BLK_ZMAP + N_ZMAP)
115 #define BLK_FIRST ztob(FIRST)
116 #define ZONE_SIZE ((int) ztob(block_size))
117 #define NLEVEL (NR_ZONE_NUMS - NR_DZONE_NUM + 1)
119 /* Byte address of a zone */
120 #define INDCHUNK ((int) (CINDIR * ZONE_NUM_SIZE))
121 #define DIRCHUNK ((int) (CDIRECT * DIR_ENTRY_SIZE))
123 char *prog, *fsck_device; /* program name (fsck), device name */
124 int firstcnterr; /* is this the first inode ref cnt error? */
125 bitchunk_t *imap, *spec_imap; /* inode bit maps */
126 bitchunk_t *zmap, *spec_zmap; /* zone bit maps */
127 bitchunk_t *dirmap; /* directory (inode) bit map */
128 char *rwbuf; /* one block buffer cache */
129 block_nr thisblk; /* block in buffer cache */
130 char *nullbuf; /* null buffer */
131 nlink_t *count; /* inode count */
132 int changed; /* has the diskette been written to? */
133 struct stack {
134 dir_struct *st_dir;
135 struct stack *st_next;
136 char st_presence;
137 } *ftop;
139 int dev; /* file descriptor of the device */
141 #define DOT 1
142 #define DOTDOT 2
144 /* Counters for each type of inode/zone. */
145 int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode;
146 int npipe, nsyml, ztype[NLEVEL];
147 long nfreezone;
149 int repair, automatic, listing, listsuper; /* flags */
150 int firstlist; /* has the listing header been printed? */
151 unsigned part_offset; /* sector offset for this partition */
152 char answer[] = "Answer questions with y or n. Then hit RETURN";
154 _PROTOTYPE(int main, (int argc, char **argv));
155 _PROTOTYPE(void initvars, (void));
156 _PROTOTYPE(void fatal, (char *s));
157 _PROTOTYPE(int eoln, (int c));
158 _PROTOTYPE(int yes, (char *question));
159 _PROTOTYPE(int atoo, (char *s));
160 _PROTOTYPE(int input, (char *buf, int size));
161 _PROTOTYPE(char *alloc, (unsigned nelem, unsigned elsize));
162 _PROTOTYPE(void printname, (char *s));
163 _PROTOTYPE(void printrec, (struct stack *sp));
164 _PROTOTYPE(void printpath, (int mode, int nlcr));
165 _PROTOTYPE(void devopen, (void));
166 _PROTOTYPE(void devclose, (void));
167 _PROTOTYPE(void devio, (block_nr bno, int dir));
168 _PROTOTYPE(void devread, (long block, long offset, char *buf, int size));
169 _PROTOTYPE(void devwrite, (long block, long offset, char *buf, int size));
170 _PROTOTYPE(void pr, (char *fmt, int cnt, char *s, char *p));
171 _PROTOTYPE(void lpr, (char *fmt, long cnt, char *s, char *p));
172 _PROTOTYPE(bit_nr getnumber, (char *s));
173 _PROTOTYPE(char **getlist, (char ***argv, char *type));
174 _PROTOTYPE(void lsuper, (void));
175 _PROTOTYPE(void getsuper, (void));
176 _PROTOTYPE(void chksuper, (void));
177 _PROTOTYPE(void lsi, (char **clist));
178 _PROTOTYPE(bitchunk_t *allocbitmap, (int nblk));
179 _PROTOTYPE(void loadbitmap, (bitchunk_t *bitmap, block_nr bno, int nblk));
180 _PROTOTYPE(void dumpbitmap, (bitchunk_t *bitmap, block_nr bno, int nblk));
181 _PROTOTYPE(void fillbitmap, (bitchunk_t *bitmap, bit_nr lwb, bit_nr upb, char **list));
182 _PROTOTYPE(void freebitmap, (bitchunk_t *p));
183 _PROTOTYPE(void getbitmaps, (void));
184 _PROTOTYPE(void putbitmaps, (void));
185 _PROTOTYPE(void chkword, (unsigned w1, unsigned w2, bit_nr bit, char *type, int *n, int *report, bit_t));
186 _PROTOTYPE(void chkmap, (bitchunk_t *cmap, bitchunk_t *dmap, bit_nr bit, block_nr blkno, int nblk, char *type));
187 _PROTOTYPE(void chkilist, (void));
188 _PROTOTYPE(void getcount, (void));
189 _PROTOTYPE(void counterror, (ino_t ino));
190 _PROTOTYPE(void chkcount, (void));
191 _PROTOTYPE(void freecount, (void));
192 _PROTOTYPE(void printperm, (mode_t mode, int shift, int special, int overlay));
193 _PROTOTYPE(void list, (ino_t ino, d_inode *ip));
194 _PROTOTYPE(int Remove, (dir_struct *dp));
195 _PROTOTYPE(void make_printable_name, (char *dst, char *src, int n));
196 _PROTOTYPE(int chkdots, (ino_t ino, off_t pos, dir_struct *dp, ino_t exp));
197 _PROTOTYPE(int chkname, (ino_t ino, dir_struct *dp));
198 _PROTOTYPE(int chkentry, (ino_t ino, off_t pos, dir_struct *dp));
199 _PROTOTYPE(int chkdirzone, (ino_t ino, d_inode *ip, off_t pos, zone_nr zno));
200 _PROTOTYPE(int chksymlinkzone, (ino_t ino, d_inode *ip, off_t pos,
201 zone_nr zno));
202 _PROTOTYPE(void errzone, (char *mess, zone_nr zno, int level, off_t pos));
203 _PROTOTYPE(int markzone, (zone_nr zno, int level, off_t pos));
204 _PROTOTYPE(int chkindzone, (ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level));
205 _PROTOTYPE(off_t jump, (int level));
206 _PROTOTYPE(int zonechk, (ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level));
207 _PROTOTYPE(int chkzones, (ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist, int len, int level));
208 _PROTOTYPE(int chkfile, (ino_t ino, d_inode *ip));
209 _PROTOTYPE(int chkdirectory, (ino_t ino, d_inode *ip));
210 _PROTOTYPE(int chklink, (ino_t ino, d_inode *ip));
211 _PROTOTYPE(int chkspecial, (ino_t ino, d_inode *ip));
212 _PROTOTYPE(int chkmode, (ino_t ino, d_inode *ip));
213 _PROTOTYPE(int chkinode, (ino_t ino, d_inode *ip));
214 _PROTOTYPE(int descendtree, (dir_struct *dp));
215 _PROTOTYPE(void chktree, (void));
216 _PROTOTYPE(void printtotal, (void));
217 _PROTOTYPE(void chkdev, (char *f, char **clist, char **ilist, char **zlist));
219 /* Initialize the variables used by this program. */
220 void initvars()
222 register level;
224 nregular = ndirectory = nblkspec = ncharspec = nbadinode = npipe = nsyml = 0;
225 for (level = 0; level < NLEVEL; level++) ztype[level] = 0;
226 changed = 0;
227 thisblk = NO_BLOCK;
228 firstlist = 1;
229 firstcnterr = 1;
232 /* Print the string `s' and exit. */
233 void fatal(s)
234 char *s;
236 printf("%s\nfatal\n", s);
237 exit(-1);
240 /* Test for end of line. */
241 int eoln(c)
242 int c;
244 return(c == EOF || c == '\n' || c == '\r');
247 /* Ask a question and get the answer unless automatic is set. */
248 int yes(question)
249 char *question;
251 register int c, answerchar;
252 static int note = 0;
254 if (!repair) {
255 printf("\n");
256 return(0);
258 printf("%s? ", question);
259 if(!note) { printf("(y=yes, n=no, q=quit, A=for yes to all) "); note = 1; }
260 if (automatic) {
261 printf("yes\n");
262 return(1);
264 fflush(stdout);
265 if ((c = answerchar = getchar()) == 'q' || c == 'Q') exit(1);
266 if(c == 'A') { automatic = 1; c = 'y'; }
267 while (!eoln(c)) c = getchar();
268 return !(answerchar == 'n' || answerchar == 'N');
271 /* Convert string to integer. Representation is octal. */
272 int atoo(s)
273 register char *s;
275 register int n = 0;
277 while ('0' <= *s && *s < '8') {
278 n <<= 3;
279 n += *s++ - '0';
281 return n;
284 /* If repairing the file system, print a prompt and get a string from user. */
285 int input(buf, size)
286 char *buf;
287 int size;
289 register char *p = buf;
291 printf("\n");
292 if (repair) {
293 printf("--> ");
294 fflush(stdout);
295 while (--size) {
296 *p = getchar();
297 if (eoln(*p)) {
298 *p = 0;
299 return(p > buf);
301 p++;
303 *p = 0;
304 while (!eoln(getchar()));
305 return(1);
307 return(0);
310 /* Allocate some memory and zero it. */
311 char *alloc(nelem, elsize)
312 unsigned nelem, elsize;
314 char *p;
316 if ((p = (char *)malloc((size_t)nelem * elsize)) == 0) {
317 fprintf(stderr, "Tried to allocate %dkB\n",
318 nelem*elsize/1024);
319 fatal("out of memory");
321 memset((void *) p, 0, (size_t)nelem * elsize);
322 return(p);
325 /* Print the name in a directory entry. */
326 void printname(s)
327 char *s;
329 register n = NAME_MAX;
330 int c;
332 do {
333 if ((c = *s) == 0) break;
334 if (!isprint(c)) c = '?';
335 putchar(c);
336 s++;
337 } while (--n);
340 /* Print the pathname given by a linked list pointed to by `sp'. The
341 * names are in reverse order.
343 void printrec(struct stack *sp)
345 if (sp->st_next != 0) {
346 printrec(sp->st_next);
347 putchar('/');
348 printname(sp->st_dir->d_name);
352 /* Print the current pathname. */
353 void printpath(mode, nlcr)
354 int mode;
355 int nlcr;
357 if (ftop->st_next == 0)
358 putchar('/');
359 else
360 printrec(ftop);
361 switch (mode) {
362 case 1:
363 printf(" (ino = %u, ", ftop->st_dir->d_inum);
364 break;
365 case 2:
366 printf(" (ino = %u)", ftop->st_dir->d_inum);
367 break;
369 if (nlcr) printf("\n");
372 /* Open the device. */
373 void devopen()
375 if ((dev = open(fsck_device, repair ? O_RDWR : O_RDONLY)) < 0) {
376 perror(fsck_device);
377 fatal("couldn't open device to fsck");
381 /* Close the device. */
382 void devclose()
384 if (close(dev) != 0) {
385 perror("close");
386 fatal("");
390 /* Read or write a block. */
391 void devio(bno, dir)
392 block_nr bno;
393 int dir;
395 int r;
397 if(!block_size) fatal("devio() with unknown block size");
398 if (dir == READING && bno == thisblk) return;
399 thisblk = bno;
401 #if 0
402 printf("%s at block %5d\n", dir == READING ? "reading " : "writing", bno);
403 #endif
404 r= lseek64(dev, btoa64(bno), SEEK_SET, NULL);
405 if (r != 0)
406 fatal("lseek64 failed");
407 if (dir == READING) {
408 if (read(dev, rwbuf, block_size) == block_size)
409 return;
410 } else {
411 if (write(dev, rwbuf, block_size) == block_size)
412 return;
415 printf("%s: can't %s block %ld (error = 0x%x)\n", prog,
416 dir == READING ? "read" : "write", (long) bno, errno);
417 if (dir == READING) {
418 printf("Continuing with a zero-filled block.\n");
419 memset(rwbuf, 0, block_size);
420 return;
422 fatal("");
425 /* Read `size' bytes from the disk starting at block 'block' and
426 * byte `offset'.
428 void devread(block, offset, buf, size)
429 long block;
430 long offset;
431 char *buf;
432 int size;
434 if(!block_size) fatal("devread() with unknown block size");
435 if (offset >= block_size)
437 block += offset/block_size;
438 offset %= block_size;
440 devio(block, READING);
441 memmove(buf, &rwbuf[offset], size);
444 /* Write `size' bytes to the disk starting at block 'block' and
445 * byte `offset'.
447 void devwrite(block, offset, buf, size)
448 long block;
449 long offset;
450 char *buf;
451 int size;
453 if(!block_size) fatal("devwrite() with unknown block size");
454 if (!repair) fatal("internal error (devwrite)");
455 if (offset >= block_size)
457 block += offset/block_size;
458 offset %= block_size;
460 if (size != block_size) devio(block, READING);
461 memmove(&rwbuf[offset], buf, size);
462 devio(block, WRITING);
463 changed = 1;
466 /* Print a string with either a singular or a plural pronoun. */
467 void pr(fmt, cnt, s, p)
468 char *fmt, *s, *p;
469 int cnt;
471 printf(fmt, cnt, cnt == 1 ? s : p);
474 /* Same as above, but with a long argument */
475 void lpr(fmt, cnt, s, p)
476 char *fmt, *s, *p;
477 long cnt;
479 printf(fmt, cnt, cnt == 1 ? s : p);
482 /* Convert string to number. */
483 bit_nr getnumber(s)
484 register char *s;
486 register bit_nr n = 0;
488 if (s == NULL)
489 return NO_BIT;
490 while (isdigit(*s))
491 n = (n << 1) + (n << 3) + *s++ - '0';
492 return (*s == '\0') ? n : NO_BIT;
495 /* See if the list pointed to by `argv' contains numbers. */
496 char **getlist(argv, type)
497 char ***argv, *type;
499 register char **list = *argv;
500 register empty = 1;
502 while (getnumber(**argv) != NO_BIT) {
503 (*argv)++;
504 empty = 0;
506 if (empty) {
507 printf("warning: no %s numbers given\n", type);
508 return(NULL);
510 return(list);
513 /* Make a listing of the super block. If `repair' is set, ask the user
514 * for changes.
516 void lsuper()
518 char buf[80];
520 do {
521 /* Most of the following atol's enrage lint, for good reason. */
522 printf("ninodes = %u", sb.s_ninodes);
523 if (input(buf, 80)) sb.s_ninodes = atol(buf);
524 printf("nzones = %ld", sb.s_zones);
525 if (input(buf, 80)) sb.s_zones = atol(buf);
526 printf("imap_blocks = %u", sb.s_imap_blocks);
527 if (input(buf, 80)) sb.s_imap_blocks = atol(buf);
528 printf("zmap_blocks = %u", sb.s_zmap_blocks);
529 if (input(buf, 80)) sb.s_zmap_blocks = atol(buf);
530 printf("firstdatazone = %u", sb.s_firstdatazone_old);
531 if (input(buf, 80)) sb.s_firstdatazone_old = atol(buf);
532 printf("log_zone_size = %u", sb.s_log_zone_size);
533 if (input(buf, 80)) sb.s_log_zone_size = atol(buf);
534 printf("maxsize = %ld", sb.s_max_size);
535 if (input(buf, 80)) sb.s_max_size = atol(buf);
536 printf("block size = %ld", sb.s_block_size);
537 if (input(buf, 80)) sb.s_block_size = atol(buf);
538 if (yes("ok now")) {
539 devwrite(0, OFFSET_SUPER_BLOCK, (char *) &sb, sizeof(sb));
540 return;
542 } while (yes("Do you want to try again"));
543 if (repair) exit(0);
546 /* Get the super block from either disk or user. Do some initial checks. */
547 void getsuper()
549 if(lseek(dev, OFFSET_SUPER_BLOCK, SEEK_SET) < 0) {
550 perror("lseek");
551 fatal("couldn't seek to super block.");
553 if(read(dev, &sb, sizeof(sb)) != sizeof(sb)) {
554 fatal("couldn't read super block.");
556 if (listsuper) lsuper();
557 if (sb.s_magic == SUPER_MAGIC) fatal("Cannot handle V1 file systems");
558 if (sb.s_magic == SUPER_V2) {
559 fs_version = 2;
560 block_size = /* STATIC_BLOCK_SIZE */ 8192;
561 } else if(sb.s_magic == SUPER_V3) {
562 fs_version = 3;
563 block_size = sb.s_block_size;
564 } else {
565 fatal("bad magic number in super block");
567 if (sb.s_ninodes <= 0) fatal("no inodes");
568 if (sb.s_zones <= 0) fatal("no zones");
569 if (sb.s_imap_blocks <= 0) fatal("no imap");
570 if (sb.s_zmap_blocks <= 0) fatal("no zmap");
571 if (sb.s_firstdatazone != 0 && sb.s_firstdatazone <= 4)
572 fatal("first data zone too small");
573 if (sb.s_log_zone_size < 0) fatal("zone size < block size");
574 if (sb.s_max_size <= 0) {
575 printf("warning: invalid max file size %ld\n", sb.s_max_size);
576 sb.s_max_size = LONG_MAX;
580 /* Check the super block for reasonable contents. */
581 void chksuper()
583 register n;
584 register off_t maxsize;
586 n = bitmapsize((bit_t) sb.s_ninodes + 1, block_size);
587 if (sb.s_magic != SUPER_V2 && sb.s_magic != SUPER_V3)
588 fatal("bad magic number in super block");
589 if (sb.s_imap_blocks < n) {
590 printf("need %d bocks for inode bitmap; only have %d\n",
591 n, sb.s_imap_blocks);
592 fatal("too few imap blocks");
594 if (sb.s_imap_blocks != n) {
595 pr("warning: expected %d imap_block%s", n, "", "s");
596 printf(" instead of %d\n", sb.s_imap_blocks);
598 n = bitmapsize((bit_t) sb.s_zones, block_size);
599 if (sb.s_zmap_blocks < n) fatal("too few zmap blocks");
600 if (sb.s_zmap_blocks != n) {
601 pr("warning: expected %d zmap_block%s", n, "", "s");
602 printf(" instead of %d\n", sb.s_zmap_blocks);
604 if (sb.s_log_zone_size >= 8 * sizeof(block_nr))
605 fatal("log_zone_size too large");
606 if (sb.s_log_zone_size > 8) printf("warning: large log_zone_size (%d)\n",
607 sb.s_log_zone_size);
608 sb.s_firstdatazone = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size;
609 if (sb.s_firstdatazone_old != 0) {
610 if (sb.s_firstdatazone_old >= sb.s_zones)
611 fatal("first data zone too large");
612 if (sb.s_firstdatazone_old < sb.s_firstdatazone)
613 fatal("first data zone too small");
614 if (sb.s_firstdatazone_old != sb.s_firstdatazone) {
615 printf("warning: expected first data zone to be %u ",
616 sb.s_firstdatazone);
617 printf("instead of %u\n", sb.s_firstdatazone_old);
618 sb.s_firstdatazone = sb.s_firstdatazone_old;
621 maxsize = MAX_FILE_POS;
622 if (((maxsize - 1) >> sb.s_log_zone_size) / block_size >= MAX_ZONES)
623 maxsize = ((long) MAX_ZONES * block_size) << sb.s_log_zone_size;
624 if(maxsize <= 0)
625 maxsize = LONG_MAX;
626 if (sb.s_max_size != maxsize) {
627 printf("warning: expected max size to be %ld ", maxsize);
628 printf("instead of %ld\n", sb.s_max_size);
632 int inoblock(int inn)
634 return div64u(mul64u(inn - 1, INODE_SIZE), block_size) + BLK_ILIST;
637 int inooff(int inn)
639 return rem64u(mul64u(inn - 1, INODE_SIZE), block_size);
642 /* Make a listing of the inodes given by `clist'. If `repair' is set, ask
643 * the user for changes.
645 void lsi(clist)
646 char **clist;
648 register bit_nr bit;
649 register ino_t ino;
650 d_inode inode, *ip = &inode;
651 char buf[80];
653 if (clist == 0) return;
654 while ((bit = getnumber(*clist++)) != NO_BIT) {
655 setbit(spec_imap, bit);
656 ino = bit;
657 do {
658 devread(inoblock(ino), inooff(ino), (char *) ip, INODE_SIZE);
659 printf("inode %u:\n", ino);
660 printf(" mode = %6o", ip->i_mode);
661 if (input(buf, 80)) ip->i_mode = atoo(buf);
662 printf(" nlinks = %6u", ip->i_nlinks);
663 if (input(buf, 80)) ip->i_nlinks = atol(buf);
664 printf(" size = %6ld", ip->i_size);
665 if (input(buf, 80)) ip->i_size = atol(buf);
666 if (yes("Write this back")) {
667 devwrite(inoblock(ino), inooff(ino), (char *) ip,
668 INODE_SIZE);
669 break;
671 } while (yes("Do you want to change it again"));
675 /* Allocate `nblk' blocks worth of bitmap. */
676 bitchunk_t *allocbitmap(nblk)
677 int nblk;
679 register bitchunk_t *bitmap;
681 bitmap = (bitchunk_t *) alloc((unsigned) nblk, block_size);
682 *bitmap |= 1;
683 return(bitmap);
686 /* Load the bitmap starting at block `bno' from disk. */
687 void loadbitmap(bitmap, bno, nblk)
688 bitchunk_t *bitmap;
689 block_nr bno;
690 int nblk;
692 register i;
693 register bitchunk_t *p;
695 p = bitmap;
696 for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
697 devread(bno, 0, (char *) p, block_size);
698 *bitmap |= 1;
701 /* Write the bitmap starting at block `bno' to disk. */
702 void dumpbitmap(bitmap, bno, nblk)
703 bitchunk_t *bitmap;
704 block_nr bno;
705 int nblk;
707 register i;
708 register bitchunk_t *p = bitmap;
710 for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
711 devwrite(bno, 0, (char *) p, block_size);
714 /* Set the bits given by `list' in the bitmap. */
715 void fillbitmap(bitmap, lwb, upb, list)
716 bitchunk_t *bitmap;
717 bit_nr lwb, upb;
718 char **list;
720 register bit_nr bit;
722 if (list == 0) return;
723 while ((bit = getnumber(*list++)) != NO_BIT)
724 if (bit < lwb || bit >= upb) {
725 if (bitmap == spec_imap)
726 printf("inode number %ld ", bit);
727 else
728 printf("zone number %ld ", bit);
729 printf("out of range (ignored)\n");
730 } else
731 setbit(bitmap, bit - lwb + 1);
734 /* Deallocate the bitmap `p'. */
735 void freebitmap(p)
736 bitchunk_t *p;
738 free((char *) p);
741 /* Get all the bitmaps used by this program. */
742 void getbitmaps()
744 imap = allocbitmap(N_IMAP);
745 zmap = allocbitmap(N_ZMAP);
746 spec_imap = allocbitmap(N_IMAP);
747 spec_zmap = allocbitmap(N_ZMAP);
748 dirmap = allocbitmap(N_IMAP);
751 /* Release all the space taken by the bitmaps. */
752 void putbitmaps()
754 freebitmap(imap);
755 freebitmap(zmap);
756 freebitmap(spec_imap);
757 freebitmap(spec_zmap);
758 freebitmap(dirmap);
761 /* `w1' and `w2' are differing words from two bitmaps that should be
762 * identical. Print what's the matter with them.
764 void chkword(w1, w2, bit, type, n, report, phys)
765 unsigned w1, w2;
766 char *type;
767 bit_nr bit;
768 int *n, *report;
769 bit_nr phys;
771 for (; (w1 | w2); w1 >>= 1, w2 >>= 1, bit++, phys++)
772 if ((w1 ^ w2) & 1 && ++(*n) % MAXPRINT == 0 && *report &&
773 (!repair || automatic || yes("stop this listing")))
774 *report = 0;
775 else if (*report)
776 if ((w1 & 1) && !(w2 & 1))
777 printf("%s %ld is missing\n", type, bit);
778 else if (!(w1 & 1) && (w2 & 1))
779 printf("%s %ld is not free\n", type, bit);
782 /* Check if the given (correct) bitmap is identical with the one that is
783 * on the disk. If not, ask if the disk should be repaired.
785 void chkmap(cmap, dmap, bit, blkno, nblk, type)
786 bitchunk_t *cmap, *dmap;
787 bit_nr bit;
788 block_nr blkno;
789 int nblk;
790 char *type;
792 register bitchunk_t *p = dmap, *q = cmap;
793 int report = 1, nerr = 0;
794 int w = nblk * WORDS_PER_BLOCK;
795 bit_nr phys = 0;
797 printf("Checking %s map\n", type);
798 loadbitmap(dmap, blkno, nblk);
799 do {
800 if (*p != *q) chkword(*p, *q, bit, type, &nerr, &report, phys);
801 p++;
802 q++;
803 bit += 8 * sizeof(bitchunk_t);
804 phys += 8 * sizeof(bitchunk_t);
805 } while (--w > 0);
807 if ((!repair || automatic) && !report) printf("etc. ");
808 if (nerr > MAXPRINT || nerr > 10) printf("%d errors found. ", nerr);
809 if (nerr != 0 && yes("install a new map")) dumpbitmap(cmap, blkno, nblk);
810 if (nerr > 0) printf("\n");
813 /* See if the inodes that aren't allocated are cleared. */
814 void chkilist()
816 register ino_t ino = 1;
817 mode_t mode;
819 printf("Checking inode list\n");
821 if (!bitset(imap, (bit_nr) ino)) {
822 devread(inoblock(ino), inooff(ino), (char *) &mode,
823 sizeof(mode));
824 if (mode != I_NOT_ALLOC) {
825 printf("mode inode %u not cleared", ino);
826 if (yes(". clear")) devwrite(inoblock(ino),
827 inooff(ino), nullbuf, INODE_SIZE);
830 while (++ino <= sb.s_ninodes && ino != 0);
831 printf("\n");
834 /* Allocate an array to maintain the inode reference counts in. */
835 void getcount()
837 count = (nlink_t *) alloc((unsigned) (sb.s_ninodes + 1), sizeof(nlink_t));
840 /* The reference count for inode `ino' is wrong. Ask if it should be adjusted. */
841 void counterror(ino_t ino)
843 d_inode inode;
845 if (firstcnterr) {
846 printf("INODE NLINK COUNT\n");
847 firstcnterr = 0;
849 devread(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
850 count[ino] += inode.i_nlinks; /* it was already subtracted; add it back */
851 printf("%5u %5u %5u", ino, (unsigned) inode.i_nlinks, count[ino]);
852 if (yes(" adjust")) {
853 if ((inode.i_nlinks = count[ino]) == 0) {
854 fatal("internal error (counterror)");
855 inode.i_mode = I_NOT_ALLOC;
856 clrbit(imap, (bit_nr) ino);
858 devwrite(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
862 /* Check if the reference count of the inodes are correct. The array `count'
863 * is maintained as follows: an entry indexed by the inode number is
864 * incremented each time a link is found; when the inode is read the link
865 * count in there is substracted from the corresponding entry in `count'.
866 * Thus, when the whole file system has been traversed, all the entries
867 * should be zero.
869 void chkcount()
871 register ino_t ino;
873 for (ino = 1; ino <= sb.s_ninodes && ino != 0; ino++)
874 if (count[ino] != 0) counterror(ino);
875 if (!firstcnterr) printf("\n");
878 /* Deallocate the `count' array. */
879 void freecount()
881 free((char *) count);
884 /* Print the inode permission bits given by mode and shift. */
885 void printperm(mode_t mode, int shift, int special, int overlay)
887 if (mode >> shift & R_BIT)
888 putchar('r');
889 else
890 putchar('-');
891 if (mode >> shift & W_BIT)
892 putchar('w');
893 else
894 putchar('-');
895 if (mode & special)
896 putchar(overlay);
897 else
898 if (mode >> shift & X_BIT)
899 putchar('x');
900 else
901 putchar('-');
904 /* List the given inode. */
905 void list(ino_t ino, d_inode *ip)
907 if (firstlist) {
908 firstlist = 0;
909 printf(" inode permission link size name\n");
911 printf("%6u ", ino);
912 switch (ip->i_mode & I_TYPE) {
913 case I_REGULAR: putchar('-'); break;
914 case I_DIRECTORY: putchar('d'); break;
915 case I_CHAR_SPECIAL: putchar('c'); break;
916 case I_BLOCK_SPECIAL: putchar('b'); break;
917 case I_NAMED_PIPE: putchar('p'); break;
918 #ifdef I_SYMBOLIC_LINK
919 case I_SYMBOLIC_LINK: putchar('l'); break;
920 #endif
921 default: putchar('?');
923 printperm(ip->i_mode, 6, I_SET_UID_BIT, 's');
924 printperm(ip->i_mode, 3, I_SET_GID_BIT, 's');
925 printperm(ip->i_mode, 0, STICKY_BIT, 't');
926 printf(" %3u ", ip->i_nlinks);
927 switch (ip->i_mode & I_TYPE) {
928 case I_CHAR_SPECIAL:
929 case I_BLOCK_SPECIAL:
930 printf(" %2x,%2x ", (dev_t) ip->i_zone[0] >> MAJOR & 0xFF,
931 (dev_t) ip->i_zone[0] >> MINOR & 0xFF);
932 break;
933 default: printf("%7ld ", ip->i_size);
935 printpath(0, 1);
938 /* Remove an entry from a directory if ok with the user.
939 * Don't name the function remove() - that is owned by ANSI, and chaos results
940 * when it is a macro.
942 int Remove(dir_struct *dp)
944 setbit(spec_imap, (bit_nr) dp->d_inum);
945 if (yes(". remove entry")) {
946 count[dp->d_inum]--;
947 memset((void *) dp, 0, sizeof(dir_struct));
948 return(1);
950 return(0);
953 /* Convert string so that embedded control characters are printable. */
954 void make_printable_name(dst, src, n)
955 register char *dst;
956 register char *src;
957 register int n;
959 register int c;
961 while (--n >= 0 && (c = *src++) != '\0') {
962 if (isprint(c) && c != '\\')
963 *dst++ = c;
964 else {
965 *dst++ = '\\';
966 switch (c) {
967 case '\\':
968 *dst++ = '\\'; break;
969 case '\b':
970 *dst++ = 'b'; break;
971 case '\f':
972 *dst++ = 'f'; break;
973 case '\n':
974 *dst++ = 'n'; break;
975 case '\r':
976 *dst++ = 'r'; break;
977 case '\t':
978 *dst++ = 't'; break;
979 default:
980 *dst++ = '0' + ((c >> 6) & 03);
981 *dst++ = '0' + ((c >> 3) & 07);
982 *dst++ = '0' + (c & 07);
986 *dst = '\0';
989 /* See if the `.' or `..' entry is as expected. */
990 int chkdots(ino_t ino, off_t pos, dir_struct *dp, ino_t exp)
992 char printable_name[4 * NAME_MAX + 1];
994 if (dp->d_inum != exp) {
995 make_printable_name(printable_name, dp->d_name, sizeof(dp->d_name));
996 printf("bad %s in ", printable_name);
997 printpath(1, 0);
998 printf("%s is linked to %u ", printable_name, dp->d_inum);
999 printf("instead of %u)", exp);
1000 setbit(spec_imap, (bit_nr) ino);
1001 setbit(spec_imap, (bit_nr) dp->d_inum);
1002 setbit(spec_imap, (bit_nr) exp);
1003 if (yes(". repair")) {
1004 count[dp->d_inum]--;
1005 dp->d_inum = exp;
1006 count[exp]++;
1007 return(0);
1009 } else if (pos != (dp->d_name[1] ? DIR_ENTRY_SIZE : 0)) {
1010 make_printable_name(printable_name, dp->d_name, sizeof(dp->d_name));
1011 printf("warning: %s has offset %ld in ", printable_name, pos);
1012 printpath(1, 0);
1013 printf("%s is linked to %u)\n", printable_name, dp->d_inum);
1014 setbit(spec_imap, (bit_nr) ino);
1015 setbit(spec_imap, (bit_nr) dp->d_inum);
1016 setbit(spec_imap, (bit_nr) exp);
1018 return(1);
1021 /* Check the name in a directory entry. */
1022 int chkname(ino_t ino, dir_struct *dp)
1024 register n = NAME_MAX + 1;
1025 register char *p = dp->d_name;
1027 if (*p == '\0') {
1028 printf("null name found in ");
1029 printpath(0, 0);
1030 setbit(spec_imap, (bit_nr) ino);
1031 if (Remove(dp)) return(0);
1033 while (*p != '\0' && --n != 0)
1034 if (*p++ == '/') {
1035 printf("found a '/' in entry of directory ");
1036 printpath(1, 0);
1037 setbit(spec_imap, (bit_nr) ino);
1038 printf("entry = '");
1039 printname(dp->d_name);
1040 printf("')");
1041 if (Remove(dp)) return(0);
1042 break;
1044 return(1);
1047 /* Check a directory entry. Here the routine `descendtree' is called
1048 * recursively to check the file or directory pointed to by the entry.
1050 int chkentry(ino_t ino, off_t pos, dir_struct *dp)
1052 if (dp->d_inum < ROOT_INODE || dp->d_inum > sb.s_ninodes) {
1053 printf("bad inode found in directory ");
1054 printpath(1, 0);
1055 printf("ino found = %u, ", dp->d_inum);
1056 printf("name = '");
1057 printname(dp->d_name);
1058 printf("')");
1059 if (yes(". remove entry")) {
1060 memset((void *) dp, 0, sizeof(dir_struct));
1061 return(0);
1063 return(1);
1065 if ((unsigned) count[dp->d_inum] == SHRT_MAX) {
1066 printf("too many links to ino %u\n", dp->d_inum);
1067 printf("discovered at entry '");
1068 printname(dp->d_name);
1069 printf("' in directory ");
1070 printpath(0, 1);
1071 if (Remove(dp)) return(0);
1073 count[dp->d_inum]++;
1074 if (strcmp(dp->d_name, ".") == 0) {
1075 ftop->st_presence |= DOT;
1076 return(chkdots(ino, pos, dp, ino));
1078 if (strcmp(dp->d_name, "..") == 0) {
1079 ftop->st_presence |= DOTDOT;
1080 return(chkdots(ino, pos, dp, ino == ROOT_INODE ? ino :
1081 ftop->st_next->st_dir->d_inum));
1083 if (!chkname(ino, dp)) return(0);
1084 if (bitset(dirmap, (bit_nr) dp->d_inum)) {
1085 printf("link to directory discovered in ");
1086 printpath(1, 0);
1087 printf("name = '");
1088 printname(dp->d_name);
1089 printf("', dir ino = %u)", dp->d_inum);
1090 return !Remove(dp);
1092 return(descendtree(dp));
1095 /* Check a zone of a directory by checking all the entries in the zone.
1096 * The zone is split up into chunks to not allocate too much stack.
1098 int chkdirzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno)
1100 dir_struct dirblk[CDIRECT];
1101 register dir_struct *dp;
1102 register n, dirty;
1103 long block= ztob(zno);
1104 register long offset = 0;
1105 register off_t size = 0;
1106 n = SCALE * (NR_DIR_ENTRIES(block_size) / CDIRECT);
1108 do {
1109 devread(block, offset, (char *) dirblk, DIRCHUNK);
1110 dirty = 0;
1111 for (dp = dirblk; dp < &dirblk[CDIRECT]; dp++) {
1112 if (dp->d_inum != NO_ENTRY && !chkentry(ino, pos, dp))
1113 dirty = 1;
1114 pos += DIR_ENTRY_SIZE;
1115 if (dp->d_inum != NO_ENTRY) size = pos;
1117 if (dirty) devwrite(block, offset, (char *) dirblk, DIRCHUNK);
1118 offset += DIRCHUNK;
1119 n--;
1120 } while (n > 0);
1122 if (size > ip->i_size) {
1123 printf("size not updated of directory ");
1124 printpath(2, 0);
1125 if (yes(". extend")) {
1126 setbit(spec_imap, (bit_nr) ino);
1127 ip->i_size = size;
1128 devwrite(inoblock(ino), inooff(ino), (char *) ip, INODE_SIZE);
1131 return(1);
1135 int chksymlinkzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno)
1137 long block;
1138 size_t len;
1139 char target[PATH_MAX+1];
1141 if (ip->i_size > PATH_MAX)
1142 fatal("chksymlinkzone: fsck program inconsistency\n");
1143 block= ztob(zno);
1144 devread(block, 0, target, ip->i_size);
1145 target[ip->i_size]= '\0';
1146 len= strlen(target);
1147 if (len != ip->i_size)
1149 printf("bad size in symbolic link (%d instead of %d) ",
1150 ip->i_size, len);
1151 printpath(2, 0);
1152 if (yes(". update")) {
1153 setbit(spec_imap, (bit_nr) ino);
1154 ip->i_size = len;
1155 devwrite(inoblock(ino), inooff(ino),
1156 (char *) ip, INODE_SIZE);
1159 return 1;
1162 /* There is something wrong with the given zone. Print some details. */
1163 void errzone(mess, zno, level, pos)
1164 char *mess;
1165 zone_nr zno;
1166 int level;
1167 off_t pos;
1169 printf("%s zone in ", mess);
1170 printpath(1, 0);
1171 printf("zno = %ld, type = ", zno);
1172 switch (level) {
1173 case 0: printf("DATA"); break;
1174 case 1: printf("SINGLE INDIRECT"); break;
1175 case 2: printf("DOUBLE INDIRECT"); break;
1176 default: printf("VERY INDIRECT");
1178 printf(", pos = %ld)\n", pos);
1181 /* Found the given zone in the given inode. Check it, and if ok, mark it
1182 * in the zone bitmap.
1184 int markzone(zno, level, pos)
1185 zone_nr zno;
1186 int level;
1187 off_t pos;
1189 register bit_nr bit = (bit_nr) zno - FIRST + 1;
1191 ztype[level]++;
1192 if (zno < FIRST || zno >= sb.s_zones) {
1193 errzone("out-of-range", zno, level, pos);
1194 return(0);
1196 if (bitset(zmap, bit)) {
1197 setbit(spec_zmap, bit);
1198 errzone("duplicate", zno, level, pos);
1199 return(0);
1201 nfreezone--;
1202 if (bitset(spec_zmap, bit)) errzone("found", zno, level, pos);
1203 setbit(zmap, bit);
1204 return(1);
1207 /* Check an indirect zone by checking all of its entries.
1208 * The zone is split up into chunks to not allocate too much stack.
1210 int chkindzone(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level)
1212 zone_nr indirect[CINDIR];
1213 register n = NR_INDIRECTS / CINDIR;
1214 long block= ztob(zno);
1215 register long offset = 0;
1217 do {
1218 devread(block, offset, (char *) indirect, INDCHUNK);
1219 if (!chkzones(ino, ip, pos, indirect, CINDIR, level - 1)) return(0);
1220 offset += INDCHUNK;
1221 } while (--n && *pos < ip->i_size);
1222 return(1);
1225 /* Return the size of a gap in the file, represented by a null zone number
1226 * at some level of indirection.
1228 off_t jump(level)
1229 int level;
1231 off_t power = ZONE_SIZE;
1233 if (level != 0) do
1234 power *= NR_INDIRECTS;
1235 while (--level);
1236 return(power);
1239 /* Check a zone, which may be either a normal data zone, a directory zone,
1240 * or an indirect zone.
1242 int zonechk(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level)
1244 if (level == 0) {
1245 if ((ip->i_mode & I_TYPE) == I_DIRECTORY &&
1246 !chkdirzone(ino, ip, *pos, zno))
1247 return(0);
1248 if ((ip->i_mode & I_TYPE) == I_SYMBOLIC_LINK &&
1249 !chksymlinkzone(ino, ip, *pos, zno))
1250 return(0);
1251 *pos += ZONE_SIZE;
1252 return(1);
1253 } else
1254 return chkindzone(ino, ip, pos, zno, level);
1257 /* Check a list of zones given by `zlist'. */
1258 int chkzones(ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist,
1259 int len, int level)
1261 register ok = 1, i;
1263 /* The check on the position in the next loop is commented out, since FS
1264 * now requires valid zone numbers in each level that is necessary and FS
1265 * always deleted all the zones in the double indirect block.
1267 for (i = 0; i < len /* && *pos < ip->i_size */ ; i++)
1268 if (zlist[i] == NO_ZONE)
1269 *pos += jump(level);
1270 else if (!markzone(zlist[i], level, *pos)) {
1271 *pos += jump(level);
1272 ok = 0;
1273 } else if (!zonechk(ino, ip, pos, zlist[i], level))
1274 ok = 0;
1275 return(ok);
1278 /* Check a file or a directory. */
1279 int chkfile(ino_t ino, d_inode *ip)
1281 register ok, i, level;
1282 off_t pos = 0;
1284 ok = chkzones(ino, ip, &pos, &ip->i_zone[0], NR_DZONE_NUM, 0);
1285 for (i = NR_DZONE_NUM, level = 1; i < NR_ZONE_NUMS; i++, level++)
1286 ok &= chkzones(ino, ip, &pos, &ip->i_zone[i], 1, level);
1287 return(ok);
1290 /* Check a directory by checking the contents. Check if . and .. are present. */
1291 int chkdirectory(ino_t ino, d_inode *ip)
1293 register ok;
1295 setbit(dirmap, (bit_nr) ino);
1296 ok = chkfile(ino, ip);
1297 if (!(ftop->st_presence & DOT)) {
1298 printf(". missing in ");
1299 printpath(2, 1);
1300 ok = 0;
1302 if (!(ftop->st_presence & DOTDOT)) {
1303 printf(".. missing in ");
1304 printpath(2, 1);
1305 ok = 0;
1307 return(ok);
1310 #ifdef I_SYMBOLIC_LINK
1312 /* Check the validity of a symbolic link. */
1313 int chklink(ino_t ino, d_inode *ip)
1315 int ok;
1317 ok = chkfile(ino, ip);
1318 if (ip->i_size <= 0 || ip->i_size > block_size) {
1319 if (ip->i_size == 0)
1320 printf("empty symbolic link ");
1321 else
1322 printf("symbolic link too large (size %ld) ", ip->i_size);
1323 printpath(2, 1);
1324 ok = 0;
1326 return(ok);
1329 #endif
1331 /* Check the validity of a special file. */
1332 int chkspecial(ino_t ino, d_inode *ip)
1334 int i, ok;
1336 ok = 1;
1337 if ((dev_t) ip->i_zone[0] == NO_DEV) {
1338 printf("illegal device number %ld for special file ", ip->i_zone[0]);
1339 printpath(2, 1);
1340 ok = 0;
1343 /* FS will not use the remaining "zone numbers" but 1.6.11++ will panic if
1344 * they are nonzero, since this should not happen.
1346 for (i = 1; i < NR_ZONE_NUMS; i++)
1347 if (ip->i_zone[i] != NO_ZONE) {
1348 printf("nonzero zone number %ld for special file ",
1349 ip->i_zone[i]);
1350 printpath(2, 1);
1351 ok = 0;
1353 return(ok);
1356 /* Check the mode and contents of an inode. */
1357 int chkmode(ino_t ino, d_inode *ip)
1359 switch (ip->i_mode & I_TYPE) {
1360 case I_REGULAR:
1361 nregular++;
1362 return chkfile(ino, ip);
1363 case I_DIRECTORY:
1364 ndirectory++;
1365 return chkdirectory(ino, ip);
1366 case I_BLOCK_SPECIAL:
1367 nblkspec++;
1368 return chkspecial(ino, ip);
1369 case I_CHAR_SPECIAL:
1370 ncharspec++;
1371 return chkspecial(ino, ip);
1372 case I_NAMED_PIPE:
1373 npipe++;
1374 return chkfile(ino, ip);
1375 #ifdef I_SYMBOLIC_LINK
1376 case I_SYMBOLIC_LINK:
1377 nsyml++;
1378 return chklink(ino, ip);
1379 #endif
1380 default:
1381 nbadinode++;
1382 printf("bad mode of ");
1383 printpath(1, 0);
1384 printf("mode = %o)", ip->i_mode);
1385 return(0);
1389 /* Check an inode. */
1390 int chkinode(ino_t ino, d_inode *ip)
1392 if (ino == ROOT_INODE && (ip->i_mode & I_TYPE) != I_DIRECTORY) {
1393 printf("root inode is not a directory ");
1394 printf("(ino = %u, mode = %o)\n", ino, ip->i_mode);
1395 fatal("");
1397 if (ip->i_nlinks == 0) {
1398 printf("link count zero of ");
1399 printpath(2, 0);
1400 return(0);
1402 nfreeinode--;
1403 setbit(imap, (bit_nr) ino);
1404 if ((unsigned) ip->i_nlinks > SHRT_MAX) {
1405 printf("link count too big in ");
1406 printpath(1, 0);
1407 printf("cnt = %u)\n", (unsigned) ip->i_nlinks);
1408 count[ino] -= SHRT_MAX;
1409 setbit(spec_imap, (bit_nr) ino);
1410 } else {
1411 count[ino] -= (unsigned) ip->i_nlinks;
1413 return chkmode(ino, ip);
1416 /* Check the directory entry pointed to by dp, by checking the inode. */
1417 int descendtree(dp)
1418 dir_struct *dp;
1420 d_inode inode;
1421 register ino_t ino = dp->d_inum;
1422 register visited;
1423 struct stack stk;
1425 stk.st_dir = dp;
1426 stk.st_next = ftop;
1427 ftop = &stk;
1428 if (bitset(spec_imap, (bit_nr) ino)) {
1429 printf("found inode %u: ", ino);
1430 printpath(0, 1);
1432 visited = bitset(imap, (bit_nr) ino);
1433 if (!visited || listing) {
1434 devread(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
1435 if (listing) list(ino, &inode);
1436 if (!visited && !chkinode(ino, &inode)) {
1437 setbit(spec_imap, (bit_nr) ino);
1438 if (yes("remove")) {
1439 count[ino] += inode.i_nlinks - 1;
1440 clrbit(imap, (bit_nr) ino);
1441 devwrite(inoblock(ino), inooff(ino),
1442 nullbuf, INODE_SIZE);
1443 memset((void *) dp, 0, sizeof(dir_struct));
1444 ftop = ftop->st_next;
1445 return(0);
1449 ftop = ftop->st_next;
1450 return(1);
1453 /* Check the file system tree. */
1454 void chktree()
1456 dir_struct dir;
1458 nfreeinode = sb.s_ninodes;
1459 nfreezone = N_DATA;
1460 dir.d_inum = ROOT_INODE;
1461 dir.d_name[0] = 0;
1462 if (!descendtree(&dir)) fatal("bad root inode");
1463 putchar('\n');
1466 /* Print the totals of all the objects found. */
1467 void printtotal()
1469 printf("blocksize = %5d ", block_size);
1470 printf("zonesize = %5d\n", ZONE_SIZE);
1471 printf("\n");
1472 pr("%8u Regular file%s\n", nregular, "", "s");
1473 pr("%8u Director%s\n", ndirectory, "y", "ies");
1474 pr("%8u Block special file%s\n", nblkspec, "", "s");
1475 pr("%8u Character special file%s\n", ncharspec, "", "s");
1476 if (nbadinode != 0) pr("%6u Bad inode%s\n", nbadinode, "", "s");
1477 pr("%8u Free inode%s\n", nfreeinode, "", "s");
1478 pr("%8u Named pipe%s\n", npipe, "", "s");
1479 pr("%8u Symbolic link%s\n", nsyml, "", "s");
1480 /* Don't print some fields.
1481 printf("\n");
1482 pr("%8u Data zone%s\n", ztype[0], "", "s");
1483 pr("%8u Single indirect zone%s\n", ztype[1], "", "s");
1484 pr("%8u Double indirect zone%s\n", ztype[2], "", "s");
1486 lpr("%8ld Free zone%s\n", nfreezone, "", "s");
1489 /* Check the device which name is given by `f'. The inodes listed by `clist'
1490 * should be listed separately, and the inodes listed by `ilist' and the zones
1491 * listed by `zlist' should be watched for while checking the file system.
1494 void chkdev(f, clist, ilist, zlist)
1495 char *f, **clist, **ilist, **zlist;
1497 if (automatic) repair = 1;
1498 fsck_device = f;
1499 initvars();
1501 devopen();
1503 getsuper();
1505 if(block_size < _MIN_BLOCK_SIZE)
1506 fatal("funny block size");
1508 if(!(rwbuf = malloc(block_size))) fatal("couldn't allocate fs buf (1)");
1509 if(!(nullbuf = malloc(block_size))) fatal("couldn't allocate fs buf (2)");
1510 memset(nullbuf, 0, block_size);
1512 chksuper();
1514 lsi(clist);
1516 getbitmaps();
1518 fillbitmap(spec_imap, (bit_nr) 1, (bit_nr) sb.s_ninodes + 1, ilist);
1519 fillbitmap(spec_zmap, (bit_nr) FIRST, (bit_nr) sb.s_zones, zlist);
1521 getcount();
1522 chktree();
1523 chkmap(zmap, spec_zmap, (bit_nr) FIRST - 1, BLK_ZMAP, N_ZMAP, "zone");
1524 chkcount();
1525 chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP, "inode");
1526 chkilist();
1527 printtotal();
1529 putbitmaps();
1530 freecount();
1531 devclose();
1533 if (changed) printf("----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
1536 int main(argc, argv)
1537 int argc;
1538 char **argv;
1540 register char **clist = 0, **ilist = 0, **zlist = 0;
1542 register devgiven = 0;
1543 register char *arg;
1545 if ((1 << BITSHIFT) != 8 * sizeof(bitchunk_t)) {
1546 printf("Fsck was compiled with the wrong BITSHIFT!\n");
1547 exit(1);
1550 sync();
1551 prog = *argv++;
1552 while ((arg = *argv++) != 0)
1553 if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) {
1554 case 'a': automatic ^= 1; break;
1555 case 'c':
1556 clist = getlist(&argv, "inode");
1557 break;
1558 case 'i':
1559 ilist = getlist(&argv, "inode");
1560 break;
1561 case 'z':
1562 zlist = getlist(&argv, "zone");
1563 break;
1564 case 'r': repair ^= 1; break;
1565 case 'l': listing ^= 1; break;
1566 case 's': listsuper ^= 1; break;
1567 default:
1568 printf("%s: unknown flag '%s'\n", prog, arg);
1570 else {
1571 chkdev(arg, clist, ilist, zlist);
1572 clist = 0;
1573 ilist = 0;
1574 zlist = 0;
1575 devgiven = 1;
1577 if (!devgiven) {
1578 printf("Usage: fsck [-acilrsz] file\n");
1579 exit(1);
1581 return(0);