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