xref: /minix/minix/commands/fsck.mfs/fsck.c (revision 83133719)
1 /* Hacks for version 1.6 */
2 
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 mfs_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
21 
22 /* fsck - file system checker		Author: Robbert van Renesse */
23 
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
31 *
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!
36 */
37 
38 #include <sys/types.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <limits.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <minix/config.h>
47 #include <minix/const.h>
48 #include <minix/type.h>
49 #include <minix/ipc.h>
50 #include "mfs/const.h"
51 #include "mfs/inode.h"
52 #include "mfs/type.h"
53 #include "mfs/mfsdir.h"
54 #include <minix/fslib.h>
55 #include <stdio.h>
56 #include <sys/stat.h>
57 #include <dirent.h>
58 
59 #include "exitvalues.h"
60 
61 #undef N_DATA
62 
63 unsigned int fs_version = 2, block_size = 0;
64 
65 #define BITSHIFT	  5	/* = log2(#bits(int)) */
66 
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 */
70 
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.
80  */
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))
87 
88 #define ZONE_CT 	360	/* default zones  (when making file system) */
89 #define INODE_CT	 95	/* default inodes (when making file system) */
90 
91 #include "mfs/super.h"
92 static struct super_block sb;
93 
94 #define STICKY_BIT	01000	/* not defined anywhere else */
95 
96 /* Ztob gives the block address of a zone
97  * btoa64 gives the byte address of a block
98  */
99 #define ztob(z)		((block_nr) (z) << sb.s_log_zone_size)
100 #define btoa64(b)	((u64_t)(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 */
103 
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)
109 
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)
118 
119 /* Byte address of a zone */
120 #define INDCHUNK	((int) (CINDIR * ZONE_NUM_SIZE))
121 #define DIRCHUNK	((int) (CDIRECT * DIR_ENTRY_SIZE))
122 
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;
138 
139 int dev;			/* file descriptor of the device */
140 
141 #define DOT	1
142 #define DOTDOT	2
143 
144 /* Counters for each type of inode/zone. */
145 int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode;
146 int nsock, npipe, nsyml, ztype[NLEVEL];
147 long nfreezone;
148 
149 int repair, notrepaired = 0, automatic, listing, listsuper;	/* flags */
150 int preen = 0, markdirty = 0;
151 int firstlist;			/* has the listing header been printed? */
152 unsigned part_offset;		/* sector offset for this partition */
153 char answer[] = "Answer questions with y or n.  Then hit RETURN";
154 
155 int main(int argc, char **argv);
156 void initvars(void);
157 void fatal(char *s);
158 int eoln(int c);
159 int yes(char *question);
160 int atoo(char *s);
161 int input(char *buf, int size);
162 char *alloc(unsigned nelem, unsigned elsize);
163 void printname(char *s);
164 void printrec(struct stack *sp);
165 void printpath(int mode, int nlcr);
166 void devopen(void);
167 void devclose(void);
168 void devio(block_nr bno, int dir);
169 void devread(long block, long offset, char *buf, int size);
170 void devwrite(long block, long offset, char *buf, int size);
171 void pr(char *fmt, int cnt, char *s, char *p);
172 void lpr(char *fmt, long cnt, char *s, char *p);
173 bit_nr getnumber(char *s);
174 char **getlist(char ***argv, char *type);
175 void lsuper(void);
176 #define SUPER_GET	0
177 #define SUPER_PUT	1
178 void rw_super(int mode);
179 void chksuper(void);
180 void lsi(char **clist);
181 bitchunk_t *allocbitmap(int nblk);
182 void loadbitmap(bitchunk_t *bitmap, block_nr bno, int nblk);
183 void dumpbitmap(bitchunk_t *bitmap, block_nr bno, int nblk);
184 void fillbitmap(bitchunk_t *bitmap, bit_nr lwb, bit_nr upb, char
185 	**list);
186 void freebitmap(bitchunk_t *p);
187 void getbitmaps(void);
188 void putbitmaps(void);
189 void chkword(unsigned w1, unsigned w2, bit_nr bit, char *type, int *n,
190 	int *report, bit_t);
191 void chkmap(bitchunk_t *cmap, bitchunk_t *dmap, bit_nr bit, block_nr
192 	blkno, int nblk, char *type);
193 void chkilist(void);
194 void getcount(void);
195 void counterror(ino_t ino);
196 void chkcount(void);
197 void freecount(void);
198 void printperm(mode_t mode, int shift, int special, int overlay);
199 void list(ino_t ino, d_inode *ip);
200 int Remove(dir_struct *dp);
201 void make_printable_name(char *dst, char *src, int n);
202 int chkdots(ino_t ino, off_t pos, dir_struct *dp, ino_t exp);
203 int chkname(ino_t ino, dir_struct *dp);
204 int chkentry(ino_t ino, off_t pos, dir_struct *dp);
205 int chkdirzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno);
206 int chksymlinkzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno);
207 void errzone(char *mess, zone_nr zno, int level, off_t pos);
208 int markzone(zone_nr zno, int level, off_t pos);
209 int chkindzone(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int
210 	level);
211 off_t jump(int level);
212 int zonechk(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level);
213 int chkzones(ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist, int
214 	len, int level);
215 int chkfile(ino_t ino, d_inode *ip);
216 int chkdirectory(ino_t ino, d_inode *ip);
217 int chklink(ino_t ino, d_inode *ip);
218 int chkspecial(ino_t ino, d_inode *ip);
219 int chkmode(ino_t ino, d_inode *ip);
220 int chkinode(ino_t ino, d_inode *ip);
221 int descendtree(dir_struct *dp);
222 void chktree(void);
223 void printtotal(void);
224 void chkdev(char *f, char **clist, char **ilist, char **zlist);
225 
226 /* Initialize the variables used by this program. */
227 void initvars()
228 {
229   register int level;
230 
231   nregular = ndirectory = nblkspec = ncharspec =
232   nbadinode = nsock = npipe = nsyml = 0;
233   for (level = 0; level < NLEVEL; level++) ztype[level] = 0;
234   changed = 0;
235   thisblk = NO_BLOCK;
236   firstlist = 1;
237   firstcnterr = 1;
238 }
239 
240 /* Print the string `s' and exit. */
241 void fatal(s)
242 char *s;
243 {
244   printf("%s\nfatal\n", s);
245   exit(FSCK_EXIT_CHECK_FAILED);
246 }
247 
248 /* Test for end of line. */
249 int eoln(c)
250 int c;
251 {
252   return(c == EOF || c == '\n' || c == '\r');
253 }
254 
255 /* Ask a question and get the answer unless automatic is set. */
256 int yes(question)
257 char *question;
258 {
259   register int c, answerchar;
260   static int note = 0;
261   int yes;
262 
263   if (!repair) {
264 	printf("\n");
265 	return(0);
266   }
267   printf("%s? ", question);
268   if(!note) { printf("(y=yes, n=no, q=quit, A=for yes to all) "); note = 1; }
269   if (automatic) {
270 	printf("yes\n");
271 	return(1);
272   }
273   fflush(stdout);
274   if ((c = answerchar = getchar()) == 'q' || c == 'Q') exit(FSCK_EXIT_CHECK_FAILED);
275   if(c == 'A') { automatic = 1; c = 'y'; }
276   while (!eoln(c)) c = getchar();
277   yes = !(answerchar == 'n' || answerchar == 'N');
278   if(!yes) notrepaired = 1;
279   return yes;
280 }
281 
282 /* Convert string to integer.  Representation is octal. */
283 int atoo(s)
284 register char *s;
285 {
286   register int n = 0;
287 
288   while ('0' <= *s && *s < '8') {
289 	n <<= 3;
290 	n += *s++ - '0';
291   }
292   return n;
293 }
294 
295 /* If repairing the file system, print a prompt and get a string from user. */
296 int input(buf, size)
297 char *buf;
298 int size;
299 {
300   register char *p = buf;
301 
302   printf("\n");
303   if (repair) {
304 	printf("--> ");
305 	fflush(stdout);
306 	while (--size) {
307 		*p = getchar();
308 		if (eoln(*p)) {
309 			*p = 0;
310 			return(p > buf);
311 		}
312 		p++;
313 	}
314 	*p = 0;
315 	while (!eoln(getchar()));
316 	return(1);
317   }
318   return(0);
319 }
320 
321 /* Allocate some memory and zero it. */
322 char *alloc(nelem, elsize)
323 unsigned nelem, elsize;
324 {
325   char *p;
326 
327   if ((p = (char *)malloc((size_t)nelem * elsize)) == 0) {
328   	fprintf(stderr, "Tried to allocate %dkB\n",
329   		nelem*elsize/1024);
330   	fatal("out of memory");
331   }
332   memset((void *) p, 0, (size_t)nelem * elsize);
333   return(p);
334 }
335 
336 /* Print the name in a directory entry. */
337 void printname(s)
338 char *s;
339 {
340   register int n = MFS_NAME_MAX;
341   int c;
342 
343   do {
344 	if ((c = *s) == 0) break;
345 	if (!isprint(c)) c = '?';
346 	putchar(c);
347 	s++;
348   } while (--n);
349 }
350 
351 /* Print the pathname given by a linked list pointed to by `sp'.  The
352  * names are in reverse order.
353  */
354 void printrec(struct stack *sp)
355 {
356   if (sp->st_next != 0) {
357 	printrec(sp->st_next);
358 	putchar('/');
359 	printname(sp->st_dir->mfs_d_name);
360   }
361 }
362 
363 /* Print the current pathname.  */
364 void printpath(mode, nlcr)
365 int mode;
366 int nlcr;
367 {
368   if (ftop->st_next == 0)
369 	putchar('/');
370   else
371 	printrec(ftop);
372   switch (mode) {
373       case 1:
374 	printf(" (ino = %u, ", ftop->st_dir->d_inum);
375 	break;
376       case 2:
377 	printf(" (ino = %u)", ftop->st_dir->d_inum);
378 	break;
379   }
380   if (nlcr) printf("\n");
381 }
382 
383 /* Open the device.  */
384 void devopen()
385 {
386   if ((dev = open(fsck_device,
387     (repair || markdirty) ? O_RDWR : O_RDONLY)) < 0) {
388 	perror(fsck_device);
389 	fatal("couldn't open device to fsck");
390   }
391 }
392 
393 /* Close the device. */
394 void devclose()
395 {
396   if (close(dev) != 0) {
397 	perror("close");
398 	fatal("");
399   }
400 }
401 
402 /* Read or write a block. */
403 void devio(bno, dir)
404 block_nr bno;
405 int dir;
406 {
407   off_t r;
408 
409   if(!block_size) fatal("devio() with unknown block size");
410   if (dir == READING && bno == thisblk) return;
411   thisblk = bno;
412 
413 #if 0
414 printf("%s at block %5d\n", dir == READING ? "reading " : "writing", bno);
415 #endif
416   r= lseek(dev, btoa64(bno), SEEK_SET);
417   if (r == (off_t)-1)
418 	fatal("lseek failed");
419   if (dir == READING) {
420 	if (read(dev, rwbuf, block_size) == block_size)
421 		return;
422   } else {
423 	if (write(dev, rwbuf, block_size) == block_size)
424 		return;
425   }
426 
427   printf("%s: can't %s block %ld (error = 0x%x)\n", prog,
428          dir == READING ? "read" : "write", (long) bno, errno);
429   if (dir == READING) {
430 	printf("Continuing with a zero-filled block.\n");
431 	memset(rwbuf, 0, block_size);
432 	return;
433   }
434   fatal("");
435 }
436 
437 /* Read `size' bytes from the disk starting at block 'block' and
438  * byte `offset'.
439  */
440 void devread(block, offset, buf, size)
441 long block;
442 long offset;
443 char *buf;
444 int size;
445 {
446   if(!block_size) fatal("devread() with unknown block size");
447   if (offset >= block_size)
448   {
449 	block += offset/block_size;
450 	offset %= block_size;
451   }
452   devio(block, READING);
453   memmove(buf, &rwbuf[offset], size);
454 }
455 
456 /* Write `size' bytes to the disk starting at block 'block' and
457  * byte `offset'.
458  */
459 void devwrite(block, offset, buf, size)
460 long block;
461 long offset;
462 char *buf;
463 int size;
464 {
465   if(!block_size) fatal("devwrite() with unknown block size");
466   if (!repair) fatal("internal error (devwrite)");
467   if (offset >= block_size)
468   {
469 	block += offset/block_size;
470 	offset %= block_size;
471   }
472   if (size != block_size) devio(block, READING);
473   memmove(&rwbuf[offset], buf, size);
474   devio(block, WRITING);
475   changed = 1;
476 }
477 
478 /* Print a string with either a singular or a plural pronoun. */
479 void pr(fmt, cnt, s, p)
480 char *fmt, *s, *p;
481 int cnt;
482 {
483   printf(fmt, cnt, cnt == 1 ? s : p);
484 }
485 
486 /* Same as above, but with a long argument */
487 void lpr(fmt, cnt, s, p)
488 char *fmt, *s, *p;
489 long cnt;
490 {
491   printf(fmt, cnt, cnt == 1 ? s : p);
492 }
493 
494 /* Convert string to number. */
495 bit_nr getnumber(s)
496 register char *s;
497 {
498   register bit_nr n = 0;
499 
500   if (s == NULL)
501 	return NO_BIT;
502   while (isdigit(*s))
503 	n = (n << 1) + (n << 3) + *s++ - '0';
504   return (*s == '\0') ? n : NO_BIT;
505 }
506 
507 /* See if the list pointed to by `argv' contains numbers. */
508 char **getlist(argv, type)
509 char ***argv, *type;
510 {
511   register char **list = *argv;
512   register int empty = 1;
513 
514   while (getnumber(**argv) != NO_BIT) {
515 	(*argv)++;
516 	empty = 0;
517   }
518   if (empty) {
519 	printf("warning: no %s numbers given\n", type);
520 	return(NULL);
521   }
522   return(list);
523 }
524 
525 /* Make a listing of the super block.  If `repair' is set, ask the user
526  * for changes.
527  */
528 void lsuper()
529 {
530   char buf[80];
531 
532   do {
533 	/* Most of the following atol's enrage lint, for good reason. */
534 	printf("ninodes       = %u", sb.s_ninodes);
535 	if (input(buf, 80)) sb.s_ninodes = atol(buf);
536 	printf("nzones        = %d", sb.s_zones);
537 	if (input(buf, 80)) sb.s_zones = atol(buf);
538 	printf("imap_blocks   = %u", sb.s_imap_blocks);
539 	if (input(buf, 80)) sb.s_imap_blocks = atol(buf);
540 	printf("zmap_blocks   = %u", sb.s_zmap_blocks);
541 	if (input(buf, 80)) sb.s_zmap_blocks = atol(buf);
542 	printf("firstdatazone = %u", sb.s_firstdatazone_old);
543 	if (input(buf, 80)) sb.s_firstdatazone_old = atol(buf);
544 	printf("log_zone_size = %u", sb.s_log_zone_size);
545 	if (input(buf, 80)) sb.s_log_zone_size = atol(buf);
546 	printf("maxsize       = %d", sb.s_max_size);
547 	if (input(buf, 80)) sb.s_max_size = atol(buf);
548 	printf("block size    = %d", sb.s_block_size);
549 	if (input(buf, 80)) sb.s_block_size = atol(buf);
550 	if (yes("ok now")) {
551 		devwrite(0, OFFSET_SUPER_BLOCK, (char *) &sb, sizeof(sb));
552 		return;
553 	}
554 	printf("flags         = ");
555 	if(sb.s_flags & MFSFLAG_CLEAN) printf("CLEAN "); else printf("DIRTY ");
556 	printf("\n");
557   } while (yes("Do you want to try again"));
558   if (repair) exit(FSCK_EXIT_OK);
559 }
560 
561 /* Get the super block from either disk or user.  Do some initial checks. */
562 void rw_super(int put)
563 {
564   if(lseek(dev, OFFSET_SUPER_BLOCK, SEEK_SET) < 0) {
565   	perror("lseek");
566   	fatal("couldn't seek to super block.");
567   }
568   if(put == SUPER_PUT)  {
569     if(write(dev, &sb, sizeof(sb)) != sizeof(sb)) {
570   	fatal("couldn't write super block.");
571     }
572     return;
573   }
574   if(read(dev, &sb, sizeof(sb)) != sizeof(sb)) {
575   	fatal("couldn't read super block.");
576   }
577   if (listsuper) lsuper();
578   if (sb.s_magic == SUPER_MAGIC) fatal("Cannot handle V1 file systems");
579   if (sb.s_magic == SUPER_V2) {
580   	fs_version = 2;
581   	block_size = /* STATIC_BLOCK_SIZE */ 8192;
582   } else if(sb.s_magic == SUPER_V3) {
583   	fs_version = 3;
584   	block_size = sb.s_block_size;
585   } else {
586   	fatal("bad magic number in super block");
587   }
588   if (sb.s_ninodes <= 0) fatal("no inodes");
589   if (sb.s_zones <= 0) fatal("no zones");
590   if (sb.s_imap_blocks <= 0) fatal("no imap");
591   if (sb.s_zmap_blocks <= 0) fatal("no zmap");
592   if (sb.s_firstdatazone != 0 && sb.s_firstdatazone <= 4)
593 	fatal("first data zone too small");
594   if (sb.s_log_zone_size < 0) fatal("zone size < block size");
595   if (sb.s_max_size <= 0) {
596 	printf("warning: invalid max file size %d\n", sb.s_max_size);
597   	sb.s_max_size = LONG_MAX;
598   }
599 }
600 
601 /* Check the super block for reasonable contents. */
602 void chksuper()
603 {
604   register int n;
605   register off_t maxsize;
606 
607   n = bitmapsize((bit_t) sb.s_ninodes + 1, block_size);
608   if (sb.s_magic != SUPER_V2 && sb.s_magic != SUPER_V3)
609   	fatal("bad magic number in super block");
610   if (sb.s_imap_blocks < n) {
611   	printf("need %d bocks for inode bitmap; only have %d\n",
612   		n, sb.s_imap_blocks);
613   	fatal("too few imap blocks");
614   }
615   if (sb.s_imap_blocks != n) {
616 	pr("warning: expected %d imap_block%s", n, "", "s");
617 	printf(" instead of %d\n", sb.s_imap_blocks);
618   }
619   n = bitmapsize((bit_t) sb.s_zones, block_size);
620   if (sb.s_zmap_blocks < n) fatal("too few zmap blocks");
621   if (sb.s_zmap_blocks != n) {
622 	pr("warning: expected %d zmap_block%s", n, "", "s");
623 	printf(" instead of %d\n", sb.s_zmap_blocks);
624   }
625   if (sb.s_log_zone_size >= 8 * sizeof(block_nr))
626 	fatal("log_zone_size too large");
627   if (sb.s_log_zone_size > 8) printf("warning: large log_zone_size (%d)\n",
628 	       sb.s_log_zone_size);
629   sb.s_firstdatazone = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size;
630   if (sb.s_firstdatazone_old != 0) {
631 	if (sb.s_firstdatazone_old >= sb.s_zones)
632 		fatal("first data zone too large");
633 	if (sb.s_firstdatazone_old < sb.s_firstdatazone)
634 		fatal("first data zone too small");
635 	if (sb.s_firstdatazone_old != sb.s_firstdatazone) {
636 		printf("warning: expected first data zone to be %u ",
637 			sb.s_firstdatazone);
638 		printf("instead of %u\n", sb.s_firstdatazone_old);
639 		sb.s_firstdatazone = sb.s_firstdatazone_old;
640 	}
641   }
642   maxsize = MAX_FILE_POS;
643   if (((maxsize - 1) >> sb.s_log_zone_size) / block_size >= MAX_ZONES)
644 	maxsize = ((long) MAX_ZONES * block_size) << sb.s_log_zone_size;
645   if(maxsize <= 0)
646 	maxsize = LONG_MAX;
647   if (sb.s_max_size != maxsize) {
648 	printf("warning: expected max size to be %d ", maxsize);
649 	printf("instead of %d\n", sb.s_max_size);
650   }
651 
652   if(sb.s_flags & MFSFLAG_MANDATORY_MASK) {
653   	fatal("unsupported feature bits - newer fsck needed");
654   }
655 }
656 
657 int inoblock(int inn)
658 {
659   return (int)(((u64_t)(inn - 1) * INODE_SIZE) / block_size) + BLK_ILIST;
660 }
661 
662 int inooff(int inn)
663 {
664   return (int)(((u64_t)(inn - 1) * INODE_SIZE) % block_size);
665 }
666 
667 /* Make a listing of the inodes given by `clist'.  If `repair' is set, ask
668  * the user for changes.
669  */
670 void lsi(clist)
671 char **clist;
672 {
673   register bit_nr bit;
674   register ino_t ino;
675   d_inode inode, *ip = &inode;
676   char buf[80];
677 
678   if (clist == 0) return;
679   while ((bit = getnumber(*clist++)) != NO_BIT) {
680 	setbit(spec_imap, bit);
681 	ino = bit;
682 	do {
683 		devread(inoblock(ino), inooff(ino), (char *) ip, INODE_SIZE);
684 		printf("inode %u:\n", ino);
685 		printf("    mode   = %6o", ip->i_mode);
686 		if (input(buf, 80)) ip->i_mode = atoo(buf);
687 		printf("    nlinks = %6u", ip->i_nlinks);
688 		if (input(buf, 80)) ip->i_nlinks = atol(buf);
689 		printf("    size   = %6d", ip->i_size);
690 		if (input(buf, 80)) ip->i_size = atol(buf);
691 		if (yes("Write this back")) {
692 			devwrite(inoblock(ino), inooff(ino), (char *) ip,
693 				INODE_SIZE);
694 			break;
695 		}
696 	} while (yes("Do you want to change it again"));
697   }
698 }
699 
700 /* Allocate `nblk' blocks worth of bitmap. */
701 bitchunk_t *allocbitmap(nblk)
702 int nblk;
703 {
704   register bitchunk_t *bitmap;
705 
706   bitmap = (bitchunk_t *) alloc((unsigned) nblk, block_size);
707   *bitmap |= 1;
708   return(bitmap);
709 }
710 
711 /* Load the bitmap starting at block `bno' from disk. */
712 void loadbitmap(bitmap, bno, nblk)
713 bitchunk_t *bitmap;
714 block_nr bno;
715 int nblk;
716 {
717   register int i;
718   register bitchunk_t *p;
719 
720   p = bitmap;
721   for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
722 	devread(bno, 0, (char *) p, block_size);
723   *bitmap |= 1;
724 }
725 
726 /* Write the bitmap starting at block `bno' to disk. */
727 void dumpbitmap(bitmap, bno, nblk)
728 bitchunk_t *bitmap;
729 block_nr bno;
730 int nblk;
731 {
732   register int i;
733   register bitchunk_t *p = bitmap;
734 
735   for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
736 	devwrite(bno, 0, (char *) p, block_size);
737 }
738 
739 /* Set the bits given by `list' in the bitmap. */
740 void fillbitmap(bitmap, lwb, upb, list)
741 bitchunk_t *bitmap;
742 bit_nr lwb, upb;
743 char **list;
744 {
745   register bit_nr bit;
746 
747   if (list == 0) return;
748   while ((bit = getnumber(*list++)) != NO_BIT)
749 	if (bit < lwb || bit >= upb) {
750 		if (bitmap == spec_imap)
751 			printf("inode number %d ", bit);
752 		else
753 			printf("zone number %d ", bit);
754 		printf("out of range (ignored)\n");
755 	} else
756 		setbit(bitmap, bit - lwb + 1);
757 }
758 
759 /* Deallocate the bitmap `p'. */
760 void freebitmap(p)
761 bitchunk_t *p;
762 {
763   free((char *) p);
764 }
765 
766 /* Get all the bitmaps used by this program. */
767 void getbitmaps()
768 {
769   imap = allocbitmap(N_IMAP);
770   zmap = allocbitmap(N_ZMAP);
771   spec_imap = allocbitmap(N_IMAP);
772   spec_zmap = allocbitmap(N_ZMAP);
773   dirmap = allocbitmap(N_IMAP);
774 }
775 
776 /* Release all the space taken by the bitmaps. */
777 void putbitmaps()
778 {
779   freebitmap(imap);
780   freebitmap(zmap);
781   freebitmap(spec_imap);
782   freebitmap(spec_zmap);
783   freebitmap(dirmap);
784 }
785 
786 /* `w1' and `w2' are differing words from two bitmaps that should be
787  * identical.  Print what's the matter with them.
788  */
789 void chkword(w1, w2, bit, type, n, report, phys)
790 unsigned w1, w2;
791 char *type;
792 bit_nr bit;
793 int *n, *report;
794 bit_nr phys;
795 {
796   for (; (w1 | w2); w1 >>= 1, w2 >>= 1, bit++, phys++)
797 	if ((w1 ^ w2) & 1 && ++(*n) % MAXPRINT == 0 && *report &&
798 	    (!repair || automatic || yes("stop this listing")))
799 		*report = 0;
800 	else {
801 	    if (*report)
802 		if ((w1 & 1) && !(w2 & 1))
803 			printf("%s %d is missing\n", type, bit);
804 		else if (!(w1 & 1) && (w2 & 1))
805 			printf("%s %d is not free\n", type, bit);
806 	}
807 }
808 
809 /* Check if the given (correct) bitmap is identical with the one that is
810  * on the disk.  If not, ask if the disk should be repaired.
811  */
812 void chkmap(cmap, dmap, bit, blkno, nblk, type)
813 bitchunk_t *cmap, *dmap;
814 bit_nr bit;
815 block_nr blkno;
816 int nblk;
817 char *type;
818 {
819   register bitchunk_t *p = dmap, *q = cmap;
820   int report = 1, nerr = 0;
821   int w = nblk * WORDS_PER_BLOCK;
822   bit_nr phys = 0;
823 
824   printf("Checking %s map. ", type);
825   if(!preen) printf("\n");
826   fflush(stdout);
827   loadbitmap(dmap, blkno, nblk);
828   do {
829 	if (*p != *q) chkword(*p, *q, bit, type, &nerr, &report, phys);
830 	p++;
831 	q++;
832 	bit += 8 * sizeof(bitchunk_t);
833 	phys += 8 * sizeof(bitchunk_t);
834   } while (--w > 0);
835 
836   if ((!repair || automatic) && !report) printf("etc. ");
837   if (nerr > MAXPRINT || nerr > 10) printf("%d errors found. ", nerr);
838   if (nerr != 0 && yes("install a new map")) dumpbitmap(cmap, blkno, nblk);
839   if (nerr > 0) printf("\n");
840 }
841 
842 /* See if the inodes that aren't allocated are cleared. */
843 void chkilist()
844 {
845   register ino_t ino = 1;
846   mode_t mode;
847 
848   printf("Checking inode list. ");
849   if(!preen) printf("\n");
850   fflush(stdout);
851   do
852 	if (!bitset(imap, (bit_nr) ino)) {
853 		devread(inoblock(ino), inooff(ino), (char *) &mode,
854 			sizeof(mode));
855 		if (mode != I_NOT_ALLOC) {
856 			printf("mode inode %u not cleared", ino);
857 			if (yes(". clear")) devwrite(inoblock(ino),
858 				inooff(ino), nullbuf, INODE_SIZE);
859 		}
860 	}
861   while (++ino <= sb.s_ninodes && ino != 0);
862   if(!preen) printf("\n");
863 }
864 
865 /* Allocate an array to maintain the inode reference counts in. */
866 void getcount()
867 {
868   count = (nlink_t *) alloc((unsigned) (sb.s_ninodes + 1), sizeof(nlink_t));
869 }
870 
871 /* The reference count for inode `ino' is wrong.  Ask if it should be adjusted. */
872 void counterror(ino_t ino)
873 {
874   d_inode inode;
875 
876   if (firstcnterr) {
877 	printf("INODE NLINK COUNT\n");
878 	firstcnterr = 0;
879   }
880   devread(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
881   count[ino] += inode.i_nlinks;	/* it was already subtracted; add it back */
882   printf("%5u %5u %5u", ino, (unsigned) inode.i_nlinks, count[ino]);
883   if (yes(" adjust")) {
884 	if ((inode.i_nlinks = count[ino]) == 0) {
885 		fatal("internal error (counterror)");
886 		inode.i_mode = I_NOT_ALLOC;
887 		clrbit(imap, (bit_nr) ino);
888 	}
889 	devwrite(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
890   }
891 }
892 
893 /* Check if the reference count of the inodes are correct.  The array `count'
894  * is maintained as follows:  an entry indexed by the inode number is
895  * incremented each time a link is found; when the inode is read the link
896  * count in there is substracted from the corresponding entry in `count'.
897  * Thus, when the whole file system has been traversed, all the entries
898  * should be zero.
899  */
900 void chkcount()
901 {
902   register ino_t ino;
903 
904   for (ino = 1; ino <= sb.s_ninodes && ino != 0; ino++)
905 	if (count[ino] != 0) counterror(ino);
906   if (!firstcnterr) printf("\n");
907 }
908 
909 /* Deallocate the `count' array. */
910 void freecount()
911 {
912   free((char *) count);
913 }
914 
915 /* Print the inode permission bits given by mode and shift. */
916 void printperm(mode_t mode, int shift, int special, int overlay)
917 {
918   if (mode >> shift & R_BIT)
919 	putchar('r');
920   else
921 	putchar('-');
922   if (mode >> shift & W_BIT)
923 	putchar('w');
924   else
925 	putchar('-');
926   if (mode & special)
927 	putchar(overlay);
928   else
929 	if (mode >> shift & X_BIT)
930 		putchar('x');
931 	else
932 		putchar('-');
933 }
934 
935 /* List the given inode. */
936 void list(ino_t ino, d_inode *ip)
937 {
938   if (firstlist) {
939 	firstlist = 0;
940 	printf(" inode permission link   size name\n");
941   }
942   printf("%6u ", ino);
943   switch (ip->i_mode & I_TYPE) {
944       case I_REGULAR:		putchar('-');	break;
945       case I_DIRECTORY:		putchar('d');	break;
946       case I_CHAR_SPECIAL:	putchar('c');	break;
947       case I_BLOCK_SPECIAL:	putchar('b');	break;
948       case I_NAMED_PIPE:	putchar('p');	break;
949       case I_UNIX_SOCKET:	putchar('s');	break;
950 #ifdef I_SYMBOLIC_LINK
951       case I_SYMBOLIC_LINK:	putchar('l');	break;
952 #endif
953       default:			putchar('?');
954 }
955   printperm(ip->i_mode, 6, I_SET_UID_BIT, 's');
956   printperm(ip->i_mode, 3, I_SET_GID_BIT, 's');
957   printperm(ip->i_mode, 0, STICKY_BIT, 't');
958   printf(" %3u ", ip->i_nlinks);
959   switch (ip->i_mode & I_TYPE) {
960       case I_CHAR_SPECIAL:
961       case I_BLOCK_SPECIAL:
962 	printf("  %2x,%2x ", major(ip->i_zone[0]), minor(ip->i_zone[0]));
963 	break;
964       default:	printf("%7d ", ip->i_size);
965   }
966   printpath(0, 1);
967 }
968 
969 /* Remove an entry from a directory if ok with the user.
970  * Don't name the function remove() - that is owned by ANSI, and chaos results
971  * when it is a macro.
972  */
973 int Remove(dir_struct *dp)
974 {
975   setbit(spec_imap, (bit_nr) dp->d_inum);
976   if (yes(". remove entry")) {
977 	count[dp->d_inum]--;
978 	memset((void *) dp, 0, sizeof(dir_struct));
979 	return(1);
980   }
981   return(0);
982 }
983 
984 /* Convert string so that embedded control characters are printable. */
985 void make_printable_name(dst, src, n)
986 register char *dst;
987 register char *src;
988 register int n;
989 {
990   register int c;
991 
992   while (--n >= 0 && (c = *src++) != '\0') {
993 	if (isprint(c) && c != '\\')
994 		*dst++ = c;
995 	else {
996 		*dst++ = '\\';
997 		switch (c) {
998 		      case '\\':
999 			*dst++ = '\\'; break;
1000 		      case '\b':
1001 			*dst++ = 'b'; break;
1002 		      case '\f':
1003 			*dst++ = 'f'; break;
1004 		      case '\n':
1005 			*dst++ = 'n'; break;
1006 		      case '\r':
1007 			*dst++ = 'r'; break;
1008 		      case '\t':
1009 			*dst++ = 't'; break;
1010 		      default:
1011 			*dst++ = '0' + ((c >> 6) & 03);
1012 			*dst++ = '0' + ((c >> 3) & 07);
1013 			*dst++ = '0' + (c & 07);
1014 		}
1015 	}
1016   }
1017   *dst = '\0';
1018 }
1019 
1020 /* See if the `.' or `..' entry is as expected. */
1021 int chkdots(ino_t ino, off_t pos, dir_struct *dp, ino_t exp)
1022 {
1023   char printable_name[4 * MFS_NAME_MAX + 1];
1024 
1025   if (dp->d_inum != exp) {
1026 	make_printable_name(printable_name, dp->mfs_d_name, sizeof(dp->mfs_d_name));
1027 	printf("bad %s in ", printable_name);
1028 	printpath(1, 0);
1029 	printf("%s is linked to %u ", printable_name, dp->d_inum);
1030 	printf("instead of %u)", exp);
1031 	setbit(spec_imap, (bit_nr) ino);
1032 	setbit(spec_imap, (bit_nr) dp->d_inum);
1033 	setbit(spec_imap, (bit_nr) exp);
1034 	if (yes(". repair")) {
1035 		count[dp->d_inum]--;
1036 		dp->d_inum = exp;
1037 		count[exp]++;
1038 		return(0);
1039 	}
1040   } else if (pos != (dp->mfs_d_name[1] ? DIR_ENTRY_SIZE : 0)) {
1041 	make_printable_name(printable_name, dp->mfs_d_name, sizeof(dp->mfs_d_name));
1042 	printf("warning: %s has offset %d in ", printable_name, pos);
1043 	printpath(1, 0);
1044 	printf("%s is linked to %u)\n", printable_name, dp->d_inum);
1045 	setbit(spec_imap, (bit_nr) ino);
1046 	setbit(spec_imap, (bit_nr) dp->d_inum);
1047 	setbit(spec_imap, (bit_nr) exp);
1048   }
1049   return(1);
1050 }
1051 
1052 /* Check the name in a directory entry. */
1053 int chkname(ino_t ino, dir_struct *dp)
1054 {
1055   register int n = MFS_NAME_MAX + 1;
1056   register char *p = dp->mfs_d_name;
1057 
1058   if (*p == '\0') {
1059 	printf("null name found in ");
1060 	printpath(0, 0);
1061 	setbit(spec_imap, (bit_nr) ino);
1062 	if (Remove(dp)) return(0);
1063   }
1064   while (*p != '\0' && --n != 0)
1065 	if (*p++ == '/') {
1066 		printf("found a '/' in entry of directory ");
1067 		printpath(1, 0);
1068 		setbit(spec_imap, (bit_nr) ino);
1069 		printf("entry = '");
1070 		printname(dp->mfs_d_name);
1071 		printf("')");
1072 		if (Remove(dp)) return(0);
1073 		break;
1074 	}
1075   return(1);
1076 }
1077 
1078 /* Check a directory entry.  Here the routine `descendtree' is called
1079  * recursively to check the file or directory pointed to by the entry.
1080  */
1081 int chkentry(ino_t ino, off_t pos, dir_struct *dp)
1082 {
1083   if (dp->d_inum < ROOT_INODE || dp->d_inum > sb.s_ninodes) {
1084 	printf("bad inode found in directory ");
1085 	printpath(1, 0);
1086 	printf("ino found = %u, ", dp->d_inum);
1087 	printf("name = '");
1088 	printname(dp->mfs_d_name);
1089 	printf("')");
1090 	if (yes(". remove entry")) {
1091 		memset((void *) dp, 0, sizeof(dir_struct));
1092 		return(0);
1093 	}
1094 	return(1);
1095   }
1096   if ((unsigned) count[dp->d_inum] == SHRT_MAX) {
1097 	printf("too many links to ino %u\n", dp->d_inum);
1098 	printf("discovered at entry '");
1099 	printname(dp->mfs_d_name);
1100 	printf("' in directory ");
1101 	printpath(0, 1);
1102 	if (Remove(dp)) return(0);
1103   }
1104   count[dp->d_inum]++;
1105   if (strcmp(dp->mfs_d_name, ".") == 0) {
1106 	ftop->st_presence |= DOT;
1107 	return(chkdots(ino, pos, dp, ino));
1108   }
1109   if (strcmp(dp->mfs_d_name, "..") == 0) {
1110 	ftop->st_presence |= DOTDOT;
1111 	return(chkdots(ino, pos, dp, ino == ROOT_INODE ? ino :
1112 			ftop->st_next->st_dir->d_inum));
1113   }
1114   if (!chkname(ino, dp)) return(0);
1115   if (bitset(dirmap, (bit_nr) dp->d_inum)) {
1116 	printf("link to directory discovered in ");
1117 	printpath(1, 0);
1118 	printf("name = '");
1119 	printname(dp->mfs_d_name);
1120 	printf("', dir ino = %u)", dp->d_inum);
1121 	return !Remove(dp);
1122   }
1123   return(descendtree(dp));
1124 }
1125 
1126 /* Check a zone of a directory by checking all the entries in the zone.
1127  * The zone is split up into chunks to not allocate too much stack.
1128  */
1129 int chkdirzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno)
1130 {
1131   dir_struct dirblk[CDIRECT];
1132   register dir_struct *dp;
1133   register int n, dirty;
1134   long block= ztob(zno);
1135   register long offset = 0;
1136   register off_t size = 0;
1137   n = SCALE * (NR_DIR_ENTRIES(block_size) / CDIRECT);
1138 
1139   do {
1140 	devread(block, offset, (char *) dirblk, DIRCHUNK);
1141 	dirty = 0;
1142 	for (dp = dirblk; dp < &dirblk[CDIRECT]; dp++) {
1143 		if (dp->d_inum != NO_ENTRY && !chkentry(ino, pos, dp))
1144 			dirty = 1;
1145 		pos += DIR_ENTRY_SIZE;
1146 		if (dp->d_inum != NO_ENTRY) size = pos;
1147 	}
1148 	if (dirty) devwrite(block, offset, (char *) dirblk, DIRCHUNK);
1149 	offset += DIRCHUNK;
1150 	n--;
1151   } while (n > 0);
1152 
1153   if (size > ip->i_size) {
1154 	printf("size not updated of directory ");
1155 	printpath(2, 0);
1156 	if (yes(". extend")) {
1157 		setbit(spec_imap, (bit_nr) ino);
1158 		ip->i_size = size;
1159 		devwrite(inoblock(ino), inooff(ino), (char *) ip, INODE_SIZE);
1160 	}
1161   }
1162   return(1);
1163 }
1164 
1165 
1166 int chksymlinkzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno)
1167 {
1168 	long block;
1169 	size_t len;
1170 	char target[PATH_MAX+1];
1171 
1172 	if (ip->i_size > PATH_MAX)
1173 		fatal("chksymlinkzone: fsck program inconsistency\n");
1174 	block= ztob(zno);
1175 	devread(block, 0, target, ip->i_size);
1176 	target[ip->i_size]= '\0';
1177 	len= strlen(target);
1178 	if (len != ip->i_size)
1179 	{
1180 		printf("bad size in symbolic link (%d instead of %d) ",
1181 			ip->i_size, len);
1182 		printpath(2, 0);
1183 		if (yes(". update")) {
1184 			setbit(spec_imap, (bit_nr) ino);
1185 			ip->i_size = len;
1186 			devwrite(inoblock(ino), inooff(ino),
1187 				(char *) ip, INODE_SIZE);
1188 		}
1189 	}
1190 	return 1;
1191 }
1192 
1193 /* There is something wrong with the given zone.  Print some details. */
1194 void errzone(mess, zno, level, pos)
1195 char *mess;
1196 zone_nr zno;
1197 int level;
1198 off_t pos;
1199 {
1200   printf("%s zone in ", mess);
1201   printpath(1, 0);
1202   printf("zno = %d, type = ", zno);
1203   switch (level) {
1204       case 0:	printf("DATA");	break;
1205       case 1:	printf("SINGLE INDIRECT");	break;
1206       case 2:	printf("DOUBLE INDIRECT");	break;
1207       default:	printf("VERY INDIRECT");
1208   }
1209   printf(", pos = %d)\n", pos);
1210 }
1211 
1212 /* Found the given zone in the given inode.  Check it, and if ok, mark it
1213  * in the zone bitmap.
1214  */
1215 int markzone(zno, level, pos)
1216 zone_nr zno;
1217 int level;
1218 off_t pos;
1219 {
1220   register bit_nr bit = (bit_nr) zno - FIRST + 1;
1221 
1222   ztype[level]++;
1223   if (zno < FIRST || zno >= sb.s_zones) {
1224 	errzone("out-of-range", zno, level, pos);
1225 	return(0);
1226   }
1227   if (bitset(zmap, bit)) {
1228 	setbit(spec_zmap, bit);
1229 	errzone("duplicate", zno, level, pos);
1230 	return(0);
1231   }
1232   nfreezone--;
1233   if (bitset(spec_zmap, bit)) errzone("found", zno, level, pos);
1234   setbit(zmap, bit);
1235   return(1);
1236 }
1237 
1238 /* Check an indirect zone by checking all of its entries.
1239  * The zone is split up into chunks to not allocate too much stack.
1240  */
1241 int chkindzone(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level)
1242 {
1243   zone_nr indirect[CINDIR];
1244   register int n = NR_INDIRECTS / CINDIR;
1245   long block= ztob(zno);
1246   register long offset = 0;
1247 
1248   do {
1249 	devread(block, offset, (char *) indirect, INDCHUNK);
1250 	if (!chkzones(ino, ip, pos, indirect, CINDIR, level - 1)) return(0);
1251 	offset += INDCHUNK;
1252   } while (--n && *pos < ip->i_size);
1253   return(1);
1254 }
1255 
1256 /* Return the size of a gap in the file, represented by a null zone number
1257  * at some level of indirection.
1258  */
1259 off_t jump(level)
1260 int level;
1261 {
1262   off_t power = ZONE_SIZE;
1263 
1264   if (level != 0) do
1265 		power *= NR_INDIRECTS;
1266 	while (--level);
1267   return(power);
1268 }
1269 
1270 /* Check a zone, which may be either a normal data zone, a directory zone,
1271  * or an indirect zone.
1272  */
1273 int zonechk(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level)
1274 {
1275   if (level == 0) {
1276 	if ((ip->i_mode & I_TYPE) == I_DIRECTORY &&
1277 	    !chkdirzone(ino, ip, *pos, zno))
1278 		return(0);
1279 	if ((ip->i_mode & I_TYPE) == I_SYMBOLIC_LINK &&
1280 	    !chksymlinkzone(ino, ip, *pos, zno))
1281 		return(0);
1282 	*pos += ZONE_SIZE;
1283 	return(1);
1284   } else
1285 	return chkindzone(ino, ip, pos, zno, level);
1286 }
1287 
1288 /* Check a list of zones given by `zlist'. */
1289 int chkzones(ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist,
1290  int len, int level)
1291 {
1292   register int ok = 1, i;
1293 
1294   /* The check on the position in the next loop is commented out, since FS
1295    * now requires valid zone numbers in each level that is necessary and FS
1296    * always deleted all the zones in the double indirect block.
1297    */
1298   for (i = 0; i < len /* && *pos < ip->i_size */ ; i++)
1299 	if (zlist[i] == NO_ZONE)
1300 		*pos += jump(level);
1301 	else if (!markzone(zlist[i], level, *pos)) {
1302 		*pos += jump(level);
1303 		ok = 0;
1304 	} else if (!zonechk(ino, ip, pos, zlist[i], level))
1305 		ok = 0;
1306   return(ok);
1307 }
1308 
1309 /* Check a file or a directory. */
1310 int chkfile(ino_t ino, d_inode *ip)
1311 {
1312   register int ok, i, level;
1313   off_t pos = 0;
1314 
1315   ok = chkzones(ino, ip, &pos, &ip->i_zone[0], NR_DZONE_NUM, 0);
1316   for (i = NR_DZONE_NUM, level = 1; i < NR_ZONE_NUMS; i++, level++)
1317 	ok &= chkzones(ino, ip, &pos, &ip->i_zone[i], 1, level);
1318   return(ok);
1319 }
1320 
1321 /* Check a directory by checking the contents.  Check if . and .. are present. */
1322 int chkdirectory(ino_t ino, d_inode *ip)
1323 {
1324   register int ok;
1325 
1326   setbit(dirmap, (bit_nr) ino);
1327   ok = chkfile(ino, ip);
1328   if (!(ftop->st_presence & DOT)) {
1329 	printf(". missing in ");
1330 	printpath(2, 1);
1331 	ok = 0;
1332   }
1333   if (!(ftop->st_presence & DOTDOT)) {
1334 	printf(".. missing in ");
1335 	printpath(2, 1);
1336 	ok = 0;
1337   }
1338   return(ok);
1339 }
1340 
1341 #ifdef I_SYMBOLIC_LINK
1342 
1343 /* Check the validity of a symbolic link. */
1344 int chklink(ino_t ino, d_inode *ip)
1345 {
1346   int ok;
1347 
1348   ok = chkfile(ino, ip);
1349   if (ip->i_size <= 0 || ip->i_size > block_size) {
1350 	if (ip->i_size == 0)
1351 		printf("empty symbolic link ");
1352 	else
1353 		printf("symbolic link too large (size %d) ", ip->i_size);
1354 	printpath(2, 1);
1355 	ok = 0;
1356   }
1357   return(ok);
1358 }
1359 
1360 #endif
1361 
1362 /* Check the validity of a special file. */
1363 int chkspecial(ino_t ino, d_inode *ip)
1364 {
1365   int i, ok;
1366 
1367   ok = 1;
1368   if ((dev_t) ip->i_zone[0] == NO_DEV) {
1369 	printf("illegal device number %d for special file ", ip->i_zone[0]);
1370 	printpath(2, 1);
1371 	ok = 0;
1372   }
1373 
1374   /* FS will not use the remaining "zone numbers" but 1.6.11++ will panic if
1375    * they are nonzero, since this should not happen.
1376    */
1377   for (i = 1; i < NR_ZONE_NUMS; i++)
1378 	if (ip->i_zone[i] != NO_ZONE) {
1379 		printf("nonzero zone number %d for special file ",
1380 		       ip->i_zone[i]);
1381 		printpath(2, 1);
1382 		ok = 0;
1383 	}
1384   return(ok);
1385 }
1386 
1387 /* Check the mode and contents of an inode. */
1388 int chkmode(ino_t ino, d_inode *ip)
1389 {
1390   switch (ip->i_mode & I_TYPE) {
1391       case I_REGULAR:
1392 	nregular++;
1393 	return chkfile(ino, ip);
1394       case I_DIRECTORY:
1395 	ndirectory++;
1396 	return chkdirectory(ino, ip);
1397       case I_BLOCK_SPECIAL:
1398 	nblkspec++;
1399 	return chkspecial(ino, ip);
1400       case I_CHAR_SPECIAL:
1401 	ncharspec++;
1402 	return chkspecial(ino, ip);
1403       case I_NAMED_PIPE:
1404 	npipe++;
1405 	return chkfile(ino, ip);
1406       case I_UNIX_SOCKET:
1407 	nsock++;
1408 	return chkfile(ino, ip);
1409 #ifdef I_SYMBOLIC_LINK
1410       case I_SYMBOLIC_LINK:
1411 	nsyml++;
1412 	return chklink(ino, ip);
1413 #endif
1414       default:
1415 	nbadinode++;
1416 	printf("bad mode of ");
1417 	printpath(1, 0);
1418 	printf("mode = %o)", ip->i_mode);
1419 	return(0);
1420   }
1421 }
1422 
1423 /* Check an inode. */
1424 int chkinode(ino_t ino, d_inode *ip)
1425 {
1426   if (ino == ROOT_INODE && (ip->i_mode & I_TYPE) != I_DIRECTORY) {
1427 	printf("root inode is not a directory ");
1428 	printf("(ino = %u, mode = %o)\n", ino, ip->i_mode);
1429 	fatal("");
1430   }
1431   if (ip->i_nlinks == 0) {
1432 	printf("link count zero of ");
1433 	printpath(2, 0);
1434 	return(0);
1435   }
1436   nfreeinode--;
1437   setbit(imap, (bit_nr) ino);
1438   if ((unsigned) ip->i_nlinks > SHRT_MAX) {
1439 	printf("link count too big in ");
1440 	printpath(1, 0);
1441 	printf("cnt = %u)\n", (unsigned) ip->i_nlinks);
1442 	count[ino] -= SHRT_MAX;
1443 	setbit(spec_imap, (bit_nr) ino);
1444   } else {
1445 	count[ino] -= (unsigned) ip->i_nlinks;
1446   }
1447   return chkmode(ino, ip);
1448 }
1449 
1450 /* Check the directory entry pointed to by dp, by checking the inode. */
1451 int descendtree(dp)
1452 dir_struct *dp;
1453 {
1454   d_inode inode;
1455   register ino_t ino = dp->d_inum;
1456   register int visited;
1457   struct stack stk;
1458 
1459   stk.st_dir = dp;
1460   stk.st_next = ftop;
1461   ftop = &stk;
1462   if (bitset(spec_imap, (bit_nr) ino)) {
1463 	printf("found inode %u: ", ino);
1464 	printpath(0, 1);
1465   }
1466   visited = bitset(imap, (bit_nr) ino);
1467   if (!visited || listing) {
1468 	devread(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
1469 	if (listing) list(ino, &inode);
1470 	if (!visited && !chkinode(ino, &inode)) {
1471 		setbit(spec_imap, (bit_nr) ino);
1472 		if (yes("remove")) {
1473 			count[ino] += inode.i_nlinks - 1;
1474 			clrbit(imap, (bit_nr) ino);
1475 			devwrite(inoblock(ino), inooff(ino),
1476 				nullbuf, INODE_SIZE);
1477 			memset((void *) dp, 0, sizeof(dir_struct));
1478 			ftop = ftop->st_next;
1479 			return(0);
1480 		}
1481 	}
1482   }
1483   ftop = ftop->st_next;
1484   return(1);
1485 }
1486 
1487 /* Check the file system tree. */
1488 void chktree()
1489 {
1490   dir_struct dir;
1491 
1492   nfreeinode = sb.s_ninodes;
1493   nfreezone = N_DATA;
1494   dir.d_inum = ROOT_INODE;
1495   dir.mfs_d_name[0] = 0;
1496   if (!descendtree(&dir)) fatal("bad root inode");
1497   putchar('\n');
1498 }
1499 
1500 /* Print the totals of all the objects found. */
1501 void printtotal()
1502 {
1503   if(preen) {
1504   	printf("%d files, %d directories, %d free inodes, %ld free zones\n",
1505 	  	nregular, ndirectory, nfreeinode, nfreezone);
1506 	return;
1507   }
1508 
1509   printf("blocksize = %5d        ", block_size);
1510   printf("zonesize  = %5d\n", ZONE_SIZE);
1511   printf("\n");
1512   pr("%8u    Regular file%s\n", nregular, "", "s");
1513   pr("%8u    Director%s\n", ndirectory, "y", "ies");
1514   pr("%8u    Block special file%s\n", nblkspec, "", "s");
1515   pr("%8u    Character special file%s\n", ncharspec, "", "s");
1516   if (nbadinode != 0) pr("%6u    Bad inode%s\n", nbadinode, "", "s");
1517   pr("%8u    Free inode%s\n", nfreeinode, "", "s");
1518   pr("%8u    Named pipe%s\n", npipe, "", "s");
1519   pr("%8u    Unix socket%s\n", nsock, "", "s");
1520   pr("%8u    Symbolic link%s\n", nsyml, "", "s");
1521 /* Don't print some fields.
1522   printf("\n");
1523   pr("%8u    Data zone%s\n",		  ztype[0],	 "",   "s");
1524   pr("%8u    Single indirect zone%s\n",	  ztype[1],	 "",   "s");
1525   pr("%8u    Double indirect zone%s\n",	  ztype[2],	 "",   "s");
1526 */
1527   lpr("%8ld    Free zone%s\n", nfreezone, "", "s");
1528 }
1529 
1530 /* Check the device which name is given by `f'.  The inodes listed by `clist'
1531  * should be listed separately, and the inodes listed by `ilist' and the zones
1532  * listed by `zlist' should be watched for while checking the file system.
1533  */
1534 
1535 void chkdev(f, clist, ilist, zlist)
1536 char *f, **clist, **ilist, **zlist;
1537 {
1538   if (automatic) repair = 1;
1539   fsck_device = f;
1540   initvars();
1541 
1542   devopen();
1543 
1544   rw_super(SUPER_GET);
1545 
1546   if(block_size < SUPER_BLOCK_BYTES)
1547   	fatal("funny block size");
1548 
1549   if(!(rwbuf = malloc(block_size))) fatal("couldn't allocate fs buf (1)");
1550   if(!(nullbuf = malloc(block_size))) fatal("couldn't allocate fs buf (2)");
1551   memset(nullbuf, 0, block_size);
1552 
1553   chksuper();
1554 
1555   if(markdirty) {
1556   	if(sb.s_flags & MFSFLAG_CLEAN) {
1557 	  	sb.s_flags &= ~MFSFLAG_CLEAN;
1558   		rw_super(SUPER_PUT);
1559   		printf("\n----- FILE SYSTEM MARKED DIRTY -----\n\n");
1560 	} else {
1561   		printf("Filesystem is already dirty.\n");
1562 	}
1563   }
1564 
1565   /* If preening, skip fsck if clean flag is on. */
1566   if(preen) {
1567   	if(sb.s_flags & MFSFLAG_CLEAN) {
1568 	  	printf("%s: clean\n", f);
1569 		return;
1570 	}
1571 	printf("%s: dirty, performing fsck\n", f);
1572   }
1573 
1574   lsi(clist);
1575 
1576   getbitmaps();
1577 
1578   fillbitmap(spec_imap, (bit_nr) 1, (bit_nr) sb.s_ninodes + 1, ilist);
1579   fillbitmap(spec_zmap, (bit_nr) FIRST, (bit_nr) sb.s_zones, zlist);
1580 
1581   getcount();
1582   chktree();
1583   chkmap(zmap, spec_zmap, (bit_nr) FIRST - 1, BLK_ZMAP, N_ZMAP, "zone");
1584   chkcount();
1585   chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP, "inode");
1586   chkilist();
1587   if(preen) printf("\n");
1588   printtotal();
1589 
1590   putbitmaps();
1591   freecount();
1592 
1593   if (changed) printf("\n----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
1594 
1595   /* If we were told to repair the FS, and the user never stopped us from
1596    * doing it, and the FS wasn't marked clean, we can mark the FS as clean.
1597    * If we were stopped from repairing, tell user about it.
1598    */
1599   if(repair && !(sb.s_flags & MFSFLAG_CLEAN)) {
1600   	if(notrepaired) {
1601   		printf("\n----- FILE SYSTEM STILL DIRTY -----\n\n");
1602 	} else {
1603 		sync();	/* update FS on disk before clean flag */
1604 	  	sb.s_flags |= MFSFLAG_CLEAN;
1605   		rw_super(SUPER_PUT);
1606   		printf("\n----- FILE SYSTEM MARKED CLEAN -----\n\n");
1607 	}
1608   }
1609 
1610   devclose();
1611 }
1612 
1613 int main(argc, argv)
1614 int argc;
1615 char **argv;
1616 {
1617   register char **clist = 0, **ilist = 0, **zlist = 0;
1618   int badflag = 0;
1619 
1620   register int devgiven = 0;
1621   register char *arg;
1622 
1623   if ((1 << BITSHIFT) != 8 * sizeof(bitchunk_t)) {
1624 	printf("Fsck was compiled with the wrong BITSHIFT!\n");
1625 	exit(FSCK_EXIT_CHECK_FAILED);
1626   }
1627 
1628   sync();
1629   prog = *argv++;
1630   while ((arg = *argv++) != 0)
1631 	if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) {
1632 		    case 'd':	markdirty = 1;	break;
1633 		    case 'p':	preen = repair = automatic = 1; break;
1634 	            case 'y':
1635 		    case 'a':	automatic ^= 1;	break;
1636 		    case 'c':
1637 			clist = getlist(&argv, "inode");
1638 			break;
1639 		    case 'i':
1640 			ilist = getlist(&argv, "inode");
1641 			break;
1642 		    case 'z':
1643 			zlist = getlist(&argv, "zone");
1644 			break;
1645 		    case 'r':	repair ^= 1;	break;
1646 		    case 'l':	listing ^= 1;	break;
1647 		    case 's':	listsuper ^= 1;	break;
1648 		    case 'f':	break;
1649 		    default:
1650 			printf("%s: unknown flag '%s'\n", prog, arg);
1651 			badflag = 1;
1652 		}
1653 	else {
1654 		chkdev(arg, clist, ilist, zlist);
1655 		clist = 0;
1656 		ilist = 0;
1657 		zlist = 0;
1658 		devgiven = 1;
1659 	}
1660   if (!devgiven || badflag) {
1661 	printf("Usage: fsck [-dyfpacilrsz] file\n");
1662 	exit(FSCK_EXIT_USAGE);
1663   }
1664   return(0);
1665 }
1666 
1667 void panic(char *fmt, ...)
1668 {
1669 	fprintf(stderr, "%s\n", fmt);
1670 	exit(1);
1671 }
1672 
1673