xref: /minix/minix/commands/fsck.mfs/fsck.c (revision 9f988b79)
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 %lld ", 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 %llu:\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 
810 /* Check if the given (correct) bitmap is identical with the one that is
811  * on the disk.  If not, ask if the disk should be repaired.
812  */
813 void chkmap(cmap, dmap, bit, blkno, nblk, type)
814 bitchunk_t *cmap, *dmap;
815 bit_nr bit;
816 block_nr blkno;
817 int nblk;
818 char *type;
819 {
820   register bitchunk_t *p = dmap, *q = cmap;
821   int report = 1, nerr = 0;
822   int w = nblk * WORDS_PER_BLOCK;
823   bit_nr phys = 0;
824 
825   printf("Checking %s map. ", type);
826   if(!preen) printf("\n");
827   fflush(stdout);
828   loadbitmap(dmap, blkno, nblk);
829   do {
830 	if (*p != *q) chkword(*p, *q, bit, type, &nerr, &report, phys);
831 	p++;
832 	q++;
833 	bit += 8 * sizeof(bitchunk_t);
834 	phys += 8 * sizeof(bitchunk_t);
835   } while (--w > 0);
836 
837   if ((!repair || automatic) && !report) printf("etc. ");
838   if (nerr > MAXPRINT || nerr > 10) printf("%d errors found. ", nerr);
839   if (nerr != 0 && yes("install a new map")) dumpbitmap(cmap, blkno, nblk);
840   if (nerr > 0) printf("\n");
841 }
842 
843 /* See if the inodes that aren't allocated are cleared. */
844 void chkilist()
845 {
846   register ino_t ino = 1;
847   mode_t mode;
848 
849   printf("Checking inode list. ");
850   if(!preen) printf("\n");
851   fflush(stdout);
852   do
853 	if (!bitset(imap, (bit_nr) ino)) {
854 		devread(inoblock(ino), inooff(ino), (char *) &mode,
855 			sizeof(mode));
856 		if (mode != I_NOT_ALLOC) {
857 			printf("mode inode %llu not cleared", ino);
858 			if (yes(". clear")) devwrite(inoblock(ino),
859 				inooff(ino), nullbuf, INODE_SIZE);
860 		}
861 	}
862   while (++ino <= sb.s_ninodes && ino != 0);
863   if(!preen) printf("\n");
864 }
865 
866 /* Allocate an array to maintain the inode reference counts in. */
867 void getcount()
868 {
869   count = (nlink_t *) alloc((unsigned) (sb.s_ninodes + 1), sizeof(nlink_t));
870 }
871 
872 /* The reference count for inode `ino' is wrong.  Ask if it should be adjusted. */
873 void counterror(ino_t ino)
874 {
875   d_inode inode;
876 
877   if (firstcnterr) {
878 	printf("INODE NLINK COUNT\n");
879 	firstcnterr = 0;
880   }
881   devread(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
882   count[ino] += inode.i_nlinks;	/* it was already subtracted; add it back */
883   printf("%5llu %5u %5u", ino, (unsigned) inode.i_nlinks, count[ino]);
884   if (yes(" adjust")) {
885 	if ((inode.i_nlinks = count[ino]) == 0) {
886 		fatal("internal error (counterror)");
887 		inode.i_mode = I_NOT_ALLOC;
888 		clrbit(imap, (bit_nr) ino);
889 	}
890 	devwrite(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
891   }
892 }
893 
894 /* Check if the reference count of the inodes are correct.  The array `count'
895  * is maintained as follows:  an entry indexed by the inode number is
896  * incremented each time a link is found; when the inode is read the link
897  * count in there is substracted from the corresponding entry in `count'.
898  * Thus, when the whole file system has been traversed, all the entries
899  * should be zero.
900  */
901 void chkcount()
902 {
903   register ino_t ino;
904 
905   for (ino = 1; ino <= sb.s_ninodes && ino != 0; ino++)
906 	if (count[ino] != 0) counterror(ino);
907   if (!firstcnterr) printf("\n");
908 }
909 
910 /* Deallocate the `count' array. */
911 void freecount()
912 {
913   free((char *) count);
914 }
915 
916 /* Print the inode permission bits given by mode and shift. */
917 void printperm(mode_t mode, int shift, int special, int overlay)
918 {
919   if (mode >> shift & R_BIT)
920 	putchar('r');
921   else
922 	putchar('-');
923   if (mode >> shift & W_BIT)
924 	putchar('w');
925   else
926 	putchar('-');
927   if (mode & special)
928 	putchar(overlay);
929   else
930 	if (mode >> shift & X_BIT)
931 		putchar('x');
932 	else
933 		putchar('-');
934 }
935 
936 /* List the given inode. */
937 void list(ino_t ino, d_inode *ip)
938 {
939   if (firstlist) {
940 	firstlist = 0;
941 	printf(" inode permission link   size name\n");
942   }
943   printf("%6llu ", ino);
944   switch (ip->i_mode & I_TYPE) {
945       case I_REGULAR:		putchar('-');	break;
946       case I_DIRECTORY:		putchar('d');	break;
947       case I_CHAR_SPECIAL:	putchar('c');	break;
948       case I_BLOCK_SPECIAL:	putchar('b');	break;
949       case I_NAMED_PIPE:	putchar('p');	break;
950       case I_UNIX_SOCKET:	putchar('s');	break;
951 #ifdef I_SYMBOLIC_LINK
952       case I_SYMBOLIC_LINK:	putchar('l');	break;
953 #endif
954       default:			putchar('?');
955 }
956   printperm(ip->i_mode, 6, I_SET_UID_BIT, 's');
957   printperm(ip->i_mode, 3, I_SET_GID_BIT, 's');
958   printperm(ip->i_mode, 0, STICKY_BIT, 't');
959   printf(" %3u ", ip->i_nlinks);
960   switch (ip->i_mode & I_TYPE) {
961       case I_CHAR_SPECIAL:
962       case I_BLOCK_SPECIAL:
963 	printf("  %2x,%2x ", major(ip->i_zone[0]), minor(ip->i_zone[0]));
964 	break;
965       default:	printf("%7d ", ip->i_size);
966   }
967   printpath(0, 1);
968 }
969 
970 /* Remove an entry from a directory if ok with the user.
971  * Don't name the function remove() - that is owned by ANSI, and chaos results
972  * when it is a macro.
973  */
974 int Remove(dir_struct *dp)
975 {
976   setbit(spec_imap, (bit_nr) dp->d_inum);
977   if (yes(". remove entry")) {
978 	count[dp->d_inum]--;
979 	memset((void *) dp, 0, sizeof(dir_struct));
980 	return(1);
981   }
982   return(0);
983 }
984 
985 /* Convert string so that embedded control characters are printable. */
986 void make_printable_name(dst, src, n)
987 register char *dst;
988 register char *src;
989 register int n;
990 {
991   register int c;
992 
993   while (--n >= 0 && (c = *src++) != '\0') {
994 	if (isprint(c) && c != '\\')
995 		*dst++ = c;
996 	else {
997 		*dst++ = '\\';
998 		switch (c) {
999 		      case '\\':
1000 			*dst++ = '\\'; break;
1001 		      case '\b':
1002 			*dst++ = 'b'; break;
1003 		      case '\f':
1004 			*dst++ = 'f'; break;
1005 		      case '\n':
1006 			*dst++ = 'n'; break;
1007 		      case '\r':
1008 			*dst++ = 'r'; break;
1009 		      case '\t':
1010 			*dst++ = 't'; break;
1011 		      default:
1012 			*dst++ = '0' + ((c >> 6) & 03);
1013 			*dst++ = '0' + ((c >> 3) & 07);
1014 			*dst++ = '0' + (c & 07);
1015 		}
1016 	}
1017   }
1018   *dst = '\0';
1019 }
1020 
1021 /* See if the `.' or `..' entry is as expected. */
1022 int chkdots(ino_t ino, off_t pos, dir_struct *dp, ino_t exp)
1023 {
1024   char printable_name[4 * MFS_NAME_MAX + 1];
1025 
1026   if (dp->d_inum != exp) {
1027 	make_printable_name(printable_name, dp->mfs_d_name,
1028 	    sizeof(dp->mfs_d_name));
1029 	printf("bad %s in ", printable_name);
1030 	printpath(1, 0);
1031 	printf("%s is linked to %u ", printable_name, dp->d_inum);
1032 	printf("instead of %llu)", exp);
1033 	setbit(spec_imap, (bit_nr) ino);
1034 	setbit(spec_imap, (bit_nr) dp->d_inum);
1035 	setbit(spec_imap, (bit_nr) exp);
1036 	if (yes(". repair")) {
1037 		count[dp->d_inum]--;
1038 		dp->d_inum = exp;
1039 		count[exp]++;
1040 		return(0);
1041 	}
1042   } else if (pos != (dp->mfs_d_name[1] ? DIR_ENTRY_SIZE : 0)) {
1043 	make_printable_name(printable_name, dp->mfs_d_name,
1044 	    sizeof(dp->mfs_d_name));
1045 	printf("warning: %s has offset %lld in ", printable_name, pos);
1046 	printpath(1, 0);
1047 	printf("%s is linked to %u)\n", printable_name, dp->d_inum);
1048 	setbit(spec_imap, (bit_nr) ino);
1049 	setbit(spec_imap, (bit_nr) dp->d_inum);
1050 	setbit(spec_imap, (bit_nr) exp);
1051   }
1052   return(1);
1053 }
1054 
1055 /* Check the name in a directory entry. */
1056 int chkname(ino_t ino, dir_struct *dp)
1057 {
1058   register int n = MFS_NAME_MAX + 1;
1059   register char *p = dp->mfs_d_name;
1060 
1061   if (*p == '\0') {
1062 	printf("null name found in ");
1063 	printpath(0, 0);
1064 	setbit(spec_imap, (bit_nr) ino);
1065 	if (Remove(dp)) return(0);
1066   }
1067   while (*p != '\0' && --n != 0)
1068 	if (*p++ == '/') {
1069 		printf("found a '/' in entry of directory ");
1070 		printpath(1, 0);
1071 		setbit(spec_imap, (bit_nr) ino);
1072 		printf("entry = '");
1073 		printname(dp->mfs_d_name);
1074 		printf("')");
1075 		if (Remove(dp)) return(0);
1076 		break;
1077 	}
1078   return(1);
1079 }
1080 
1081 /* Check a directory entry.  Here the routine `descendtree' is called
1082  * recursively to check the file or directory pointed to by the entry.
1083  */
1084 int chkentry(ino_t ino, off_t pos, dir_struct *dp)
1085 {
1086   if (dp->d_inum < ROOT_INODE || dp->d_inum > sb.s_ninodes) {
1087 	printf("bad inode found in directory ");
1088 	printpath(1, 0);
1089 	printf("ino found = %u, ", dp->d_inum);
1090 	printf("name = '");
1091 	printname(dp->mfs_d_name);
1092 	printf("')");
1093 	if (yes(". remove entry")) {
1094 		memset((void *) dp, 0, sizeof(dir_struct));
1095 		return(0);
1096 	}
1097 	return(1);
1098   }
1099   if ((unsigned) count[dp->d_inum] == SHRT_MAX) {
1100 	printf("too many links to ino %u\n", dp->d_inum);
1101 	printf("discovered at entry '");
1102 	printname(dp->mfs_d_name);
1103 	printf("' in directory ");
1104 	printpath(0, 1);
1105 	if (Remove(dp)) return(0);
1106   }
1107   count[dp->d_inum]++;
1108   if (strcmp(dp->mfs_d_name, ".") == 0) {
1109 	ftop->st_presence |= DOT;
1110 	return(chkdots(ino, pos, dp, ino));
1111   }
1112   if (strcmp(dp->mfs_d_name, "..") == 0) {
1113 	ftop->st_presence |= DOTDOT;
1114 	return(chkdots(ino, pos, dp, ino == ROOT_INODE ? ino :
1115 			ftop->st_next->st_dir->d_inum));
1116   }
1117   if (!chkname(ino, dp)) return(0);
1118   if (bitset(dirmap, (bit_nr) dp->d_inum)) {
1119 	printf("link to directory discovered in ");
1120 	printpath(1, 0);
1121 	printf("name = '");
1122 	printname(dp->mfs_d_name);
1123 	printf("', dir ino = %u)", dp->d_inum);
1124 	return !Remove(dp);
1125   }
1126   return(descendtree(dp));
1127 }
1128 
1129 /* Check a zone of a directory by checking all the entries in the zone.
1130  * The zone is split up into chunks to not allocate too much stack.
1131  */
1132 int chkdirzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno)
1133 {
1134   dir_struct dirblk[CDIRECT];
1135   register dir_struct *dp;
1136   register int n, dirty;
1137   long block= ztob(zno);
1138   register long offset = 0;
1139   register off_t size = 0;
1140   n = SCALE * (NR_DIR_ENTRIES(block_size) / CDIRECT);
1141 
1142   do {
1143 	devread(block, offset, (char *) dirblk, DIRCHUNK);
1144 	dirty = 0;
1145 	for (dp = dirblk; dp < &dirblk[CDIRECT]; dp++) {
1146 		if (dp->d_inum != NO_ENTRY && !chkentry(ino, pos, dp))
1147 			dirty = 1;
1148 		pos += DIR_ENTRY_SIZE;
1149 		if (dp->d_inum != NO_ENTRY) size = pos;
1150 	}
1151 	if (dirty) devwrite(block, offset, (char *) dirblk, DIRCHUNK);
1152 	offset += DIRCHUNK;
1153 	n--;
1154   } while (n > 0);
1155 
1156   if (size > ip->i_size) {
1157 	printf("size not updated of directory ");
1158 	printpath(2, 0);
1159 	if (yes(". extend")) {
1160 		setbit(spec_imap, (bit_nr) ino);
1161 		ip->i_size = size;
1162 		devwrite(inoblock(ino), inooff(ino), (char *) ip, INODE_SIZE);
1163 	}
1164   }
1165   return(1);
1166 }
1167 
1168 
1169 int chksymlinkzone(ino_t ino, d_inode *ip, off_t pos, zone_nr zno)
1170 {
1171 	long block;
1172 	size_t len;
1173 	char target[PATH_MAX+1];
1174 
1175 	if (ip->i_size > PATH_MAX)
1176 		fatal("chksymlinkzone: fsck program inconsistency\n");
1177 	block= ztob(zno);
1178 	devread(block, 0, target, ip->i_size);
1179 	target[ip->i_size]= '\0';
1180 	len= strlen(target);
1181 	if (len != ip->i_size)
1182 	{
1183 		printf("bad size in symbolic link (%d instead of %d) ",
1184 			ip->i_size, len);
1185 		printpath(2, 0);
1186 		if (yes(". update")) {
1187 			setbit(spec_imap, (bit_nr) ino);
1188 			ip->i_size = len;
1189 			devwrite(inoblock(ino), inooff(ino),
1190 				(char *) ip, INODE_SIZE);
1191 		}
1192 	}
1193 	return 1;
1194 }
1195 
1196 /* There is something wrong with the given zone.  Print some details. */
1197 void errzone(mess, zno, level, pos)
1198 char *mess;
1199 zone_nr zno;
1200 int level;
1201 off_t pos;
1202 {
1203   printf("%s zone in ", mess);
1204   printpath(1, 0);
1205   printf("zno = %d, type = ", zno);
1206   switch (level) {
1207       case 0:	printf("DATA");	break;
1208       case 1:	printf("SINGLE INDIRECT");	break;
1209       case 2:	printf("DOUBLE INDIRECT");	break;
1210       default:	printf("VERY INDIRECT");
1211   }
1212   printf(", pos = %lld)\n", pos);
1213 }
1214 
1215 /* Found the given zone in the given inode.  Check it, and if ok, mark it
1216  * in the zone bitmap.
1217  */
1218 int markzone(zno, level, pos)
1219 zone_nr zno;
1220 int level;
1221 off_t pos;
1222 {
1223   register bit_nr bit = (bit_nr) zno - FIRST + 1;
1224 
1225   ztype[level]++;
1226   if (zno < FIRST || zno >= sb.s_zones) {
1227 	errzone("out-of-range", zno, level, pos);
1228 	return(0);
1229   }
1230   if (bitset(zmap, bit)) {
1231 	setbit(spec_zmap, bit);
1232 	errzone("duplicate", zno, level, pos);
1233 	return(0);
1234   }
1235   nfreezone--;
1236   if (bitset(spec_zmap, bit)) errzone("found", zno, level, pos);
1237   setbit(zmap, bit);
1238   return(1);
1239 }
1240 
1241 /* Check an indirect zone by checking all of its entries.
1242  * The zone is split up into chunks to not allocate too much stack.
1243  */
1244 int chkindzone(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level)
1245 {
1246   zone_nr indirect[CINDIR];
1247   register int n = NR_INDIRECTS / CINDIR;
1248   long block= ztob(zno);
1249   register long offset = 0;
1250 
1251   do {
1252 	devread(block, offset, (char *) indirect, INDCHUNK);
1253 	if (!chkzones(ino, ip, pos, indirect, CINDIR, level - 1)) return(0);
1254 	offset += INDCHUNK;
1255   } while (--n && *pos < ip->i_size);
1256   return(1);
1257 }
1258 
1259 /* Return the size of a gap in the file, represented by a null zone number
1260  * at some level of indirection.
1261  */
1262 off_t jump(level)
1263 int level;
1264 {
1265   off_t power = ZONE_SIZE;
1266 
1267   if (level != 0) do
1268 		power *= NR_INDIRECTS;
1269 	while (--level);
1270   return(power);
1271 }
1272 
1273 /* Check a zone, which may be either a normal data zone, a directory zone,
1274  * or an indirect zone.
1275  */
1276 int zonechk(ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level)
1277 {
1278   if (level == 0) {
1279 	if ((ip->i_mode & I_TYPE) == I_DIRECTORY &&
1280 	    !chkdirzone(ino, ip, *pos, zno))
1281 		return(0);
1282 	if ((ip->i_mode & I_TYPE) == I_SYMBOLIC_LINK &&
1283 	    !chksymlinkzone(ino, ip, *pos, zno))
1284 		return(0);
1285 	*pos += ZONE_SIZE;
1286 	return(1);
1287   } else
1288 	return chkindzone(ino, ip, pos, zno, level);
1289 }
1290 
1291 /* Check a list of zones given by `zlist'. */
1292 int chkzones(ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist,
1293  int len, int level)
1294 {
1295   register int ok = 1, i;
1296 
1297   /* The check on the position in the next loop is commented out, since FS
1298    * now requires valid zone numbers in each level that is necessary and FS
1299    * always deleted all the zones in the double indirect block.
1300    */
1301   for (i = 0; i < len /* && *pos < ip->i_size */ ; i++)
1302 	if (zlist[i] == NO_ZONE)
1303 		*pos += jump(level);
1304 	else if (!markzone(zlist[i], level, *pos)) {
1305 		*pos += jump(level);
1306 		ok = 0;
1307 	} else if (!zonechk(ino, ip, pos, zlist[i], level))
1308 		ok = 0;
1309   return(ok);
1310 }
1311 
1312 /* Check a file or a directory. */
1313 int chkfile(ino_t ino, d_inode *ip)
1314 {
1315   register int ok, i, level;
1316   off_t pos = 0;
1317 
1318   ok = chkzones(ino, ip, &pos, &ip->i_zone[0], NR_DZONE_NUM, 0);
1319   for (i = NR_DZONE_NUM, level = 1; i < NR_ZONE_NUMS; i++, level++)
1320 	ok &= chkzones(ino, ip, &pos, &ip->i_zone[i], 1, level);
1321   return(ok);
1322 }
1323 
1324 /* Check a directory by checking the contents.  Check if . and .. are present. */
1325 int chkdirectory(ino_t ino, d_inode *ip)
1326 {
1327   register int ok;
1328 
1329   setbit(dirmap, (bit_nr) ino);
1330   ok = chkfile(ino, ip);
1331   if (!(ftop->st_presence & DOT)) {
1332 	printf(". missing in ");
1333 	printpath(2, 1);
1334 	ok = 0;
1335   }
1336   if (!(ftop->st_presence & DOTDOT)) {
1337 	printf(".. missing in ");
1338 	printpath(2, 1);
1339 	ok = 0;
1340   }
1341   return(ok);
1342 }
1343 
1344 #ifdef I_SYMBOLIC_LINK
1345 
1346 /* Check the validity of a symbolic link. */
1347 int chklink(ino_t ino, d_inode *ip)
1348 {
1349   int ok;
1350 
1351   ok = chkfile(ino, ip);
1352   if (ip->i_size <= 0 || ip->i_size > block_size) {
1353 	if (ip->i_size == 0)
1354 		printf("empty symbolic link ");
1355 	else
1356 		printf("symbolic link too large (size %d) ", ip->i_size);
1357 	printpath(2, 1);
1358 	ok = 0;
1359   }
1360   return(ok);
1361 }
1362 
1363 #endif
1364 
1365 /* Check the validity of a special file. */
1366 int chkspecial(ino_t ino, d_inode *ip)
1367 {
1368   int i, ok;
1369 
1370   ok = 1;
1371   if ((dev_t) ip->i_zone[0] == NO_DEV) {
1372 	printf("illegal device number %d for special file ", ip->i_zone[0]);
1373 	printpath(2, 1);
1374 	ok = 0;
1375   }
1376 
1377   /* FS will not use the remaining "zone numbers" but 1.6.11++ will panic if
1378    * they are nonzero, since this should not happen.
1379    */
1380   for (i = 1; i < NR_ZONE_NUMS; i++)
1381 	if (ip->i_zone[i] != NO_ZONE) {
1382 		printf("nonzero zone number %d for special file ",
1383 		       ip->i_zone[i]);
1384 		printpath(2, 1);
1385 		ok = 0;
1386 	}
1387   return(ok);
1388 }
1389 
1390 /* Check the mode and contents of an inode. */
1391 int chkmode(ino_t ino, d_inode *ip)
1392 {
1393   switch (ip->i_mode & I_TYPE) {
1394       case I_REGULAR:
1395 	nregular++;
1396 	return chkfile(ino, ip);
1397       case I_DIRECTORY:
1398 	ndirectory++;
1399 	return chkdirectory(ino, ip);
1400       case I_BLOCK_SPECIAL:
1401 	nblkspec++;
1402 	return chkspecial(ino, ip);
1403       case I_CHAR_SPECIAL:
1404 	ncharspec++;
1405 	return chkspecial(ino, ip);
1406       case I_NAMED_PIPE:
1407 	npipe++;
1408 	return chkfile(ino, ip);
1409       case I_UNIX_SOCKET:
1410 	nsock++;
1411 	return chkfile(ino, ip);
1412 #ifdef I_SYMBOLIC_LINK
1413       case I_SYMBOLIC_LINK:
1414 	nsyml++;
1415 	return chklink(ino, ip);
1416 #endif
1417       default:
1418 	nbadinode++;
1419 	printf("bad mode of ");
1420 	printpath(1, 0);
1421 	printf("mode = %o)", ip->i_mode);
1422 	return(0);
1423   }
1424 }
1425 
1426 /* Check an inode. */
1427 int chkinode(ino_t ino, d_inode *ip)
1428 {
1429   if (ino == ROOT_INODE && (ip->i_mode & I_TYPE) != I_DIRECTORY) {
1430 	printf("root inode is not a directory ");
1431 	printf("(ino = %llu, mode = %o)\n", ino, ip->i_mode);
1432 	fatal("");
1433   }
1434   if (ip->i_nlinks == 0) {
1435 	printf("link count zero of ");
1436 	printpath(2, 0);
1437 	return(0);
1438   }
1439   nfreeinode--;
1440   setbit(imap, (bit_nr) ino);
1441   if ((unsigned) ip->i_nlinks > SHRT_MAX) {
1442 	printf("link count too big in ");
1443 	printpath(1, 0);
1444 	printf("cnt = %u)\n", (unsigned) ip->i_nlinks);
1445 	count[ino] -= SHRT_MAX;
1446 	setbit(spec_imap, (bit_nr) ino);
1447   } else {
1448 	count[ino] -= (unsigned) ip->i_nlinks;
1449   }
1450   return chkmode(ino, ip);
1451 }
1452 
1453 /* Check the directory entry pointed to by dp, by checking the inode. */
1454 int descendtree(dp)
1455 dir_struct *dp;
1456 {
1457   d_inode inode;
1458   register ino_t ino = dp->d_inum;
1459   register int visited;
1460   struct stack stk;
1461 
1462   stk.st_dir = dp;
1463   stk.st_next = ftop;
1464   ftop = &stk;
1465   if (bitset(spec_imap, (bit_nr) ino)) {
1466 	printf("found inode %llu: ", ino);
1467 	printpath(0, 1);
1468   }
1469   visited = bitset(imap, (bit_nr) ino);
1470   if (!visited || listing) {
1471 	devread(inoblock(ino), inooff(ino), (char *) &inode, INODE_SIZE);
1472 	if (listing) list(ino, &inode);
1473 	if (!visited && !chkinode(ino, &inode)) {
1474 		setbit(spec_imap, (bit_nr) ino);
1475 		if (yes("remove")) {
1476 			count[ino] += inode.i_nlinks - 1;
1477 			clrbit(imap, (bit_nr) ino);
1478 			devwrite(inoblock(ino), inooff(ino),
1479 				nullbuf, INODE_SIZE);
1480 			memset((void *) dp, 0, sizeof(dir_struct));
1481 			ftop = ftop->st_next;
1482 			return(0);
1483 		}
1484 	}
1485   }
1486   ftop = ftop->st_next;
1487   return(1);
1488 }
1489 
1490 /* Check the file system tree. */
1491 void chktree()
1492 {
1493   dir_struct dir;
1494 
1495   nfreeinode = sb.s_ninodes;
1496   nfreezone = N_DATA;
1497   dir.d_inum = ROOT_INODE;
1498   dir.mfs_d_name[0] = 0;
1499   if (!descendtree(&dir)) fatal("bad root inode");
1500   putchar('\n');
1501 }
1502 
1503 /* Print the totals of all the objects found. */
1504 void printtotal()
1505 {
1506   if(preen) {
1507   	printf("%d files, %d directories, %d free inodes, %ld free zones\n",
1508 	  	nregular, ndirectory, nfreeinode, nfreezone);
1509 	return;
1510   }
1511 
1512   printf("blocksize = %5d        ", block_size);
1513   printf("zonesize  = %5d\n", ZONE_SIZE);
1514   printf("\n");
1515   pr("%8u    Regular file%s\n", nregular, "", "s");
1516   pr("%8u    Director%s\n", ndirectory, "y", "ies");
1517   pr("%8u    Block special file%s\n", nblkspec, "", "s");
1518   pr("%8u    Character special file%s\n", ncharspec, "", "s");
1519   if (nbadinode != 0) pr("%6u    Bad inode%s\n", nbadinode, "", "s");
1520   pr("%8u    Free inode%s\n", nfreeinode, "", "s");
1521   pr("%8u    Named pipe%s\n", npipe, "", "s");
1522   pr("%8u    Unix socket%s\n", nsock, "", "s");
1523   pr("%8u    Symbolic link%s\n", nsyml, "", "s");
1524 /* Don't print some fields.
1525   printf("\n");
1526   pr("%8u    Data zone%s\n",		  ztype[0],	 "",   "s");
1527   pr("%8u    Single indirect zone%s\n",	  ztype[1],	 "",   "s");
1528   pr("%8u    Double indirect zone%s\n",	  ztype[2],	 "",   "s");
1529 */
1530   lpr("%8ld    Free zone%s\n", nfreezone, "", "s");
1531 }
1532 
1533 /* Check the device which name is given by `f'.  The inodes listed by `clist'
1534  * should be listed separately, and the inodes listed by `ilist' and the zones
1535  * listed by `zlist' should be watched for while checking the file system.
1536  */
1537 
1538 void chkdev(f, clist, ilist, zlist)
1539 char *f, **clist, **ilist, **zlist;
1540 {
1541   if (automatic) repair = 1;
1542   fsck_device = f;
1543   initvars();
1544 
1545   devopen();
1546 
1547   rw_super(SUPER_GET);
1548 
1549   if(block_size < SUPER_BLOCK_BYTES)
1550   	fatal("funny block size");
1551 
1552   if(!(rwbuf = malloc(block_size))) fatal("couldn't allocate fs buf (1)");
1553   if(!(nullbuf = malloc(block_size))) fatal("couldn't allocate fs buf (2)");
1554   memset(nullbuf, 0, block_size);
1555 
1556   chksuper();
1557 
1558   if(markdirty) {
1559   	if(sb.s_flags & MFSFLAG_CLEAN) {
1560 	  	sb.s_flags &= ~MFSFLAG_CLEAN;
1561   		rw_super(SUPER_PUT);
1562   		printf("\n----- FILE SYSTEM MARKED DIRTY -----\n\n");
1563 	} else {
1564   		printf("Filesystem is already dirty.\n");
1565 	}
1566   }
1567 
1568   /* If preening, skip fsck if clean flag is on. */
1569   if(preen) {
1570   	if(sb.s_flags & MFSFLAG_CLEAN) {
1571 	  	printf("%s: clean\n", f);
1572 		return;
1573 	}
1574 	printf("%s: dirty, performing fsck\n", f);
1575   }
1576 
1577   lsi(clist);
1578 
1579   getbitmaps();
1580 
1581   fillbitmap(spec_imap, (bit_nr) 1, (bit_nr) sb.s_ninodes + 1, ilist);
1582   fillbitmap(spec_zmap, (bit_nr) FIRST, (bit_nr) sb.s_zones, zlist);
1583 
1584   getcount();
1585   chktree();
1586   chkmap(zmap, spec_zmap, (bit_nr) FIRST - 1, BLK_ZMAP, N_ZMAP, "zone");
1587   chkcount();
1588   chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP, "inode");
1589   chkilist();
1590   if(preen) printf("\n");
1591   printtotal();
1592 
1593   putbitmaps();
1594   freecount();
1595 
1596   if (changed) printf("\n----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
1597 
1598   /* If we were told to repair the FS, and the user never stopped us from
1599    * doing it, and the FS wasn't marked clean, we can mark the FS as clean.
1600    * If we were stopped from repairing, tell user about it.
1601    */
1602   if(repair && !(sb.s_flags & MFSFLAG_CLEAN)) {
1603   	if(notrepaired) {
1604   		printf("\n----- FILE SYSTEM STILL DIRTY -----\n\n");
1605 	} else {
1606 		sync();	/* update FS on disk before clean flag */
1607 	  	sb.s_flags |= MFSFLAG_CLEAN;
1608   		rw_super(SUPER_PUT);
1609   		printf("\n----- FILE SYSTEM MARKED CLEAN -----\n\n");
1610 	}
1611   }
1612 
1613   devclose();
1614 }
1615 
1616 int main(argc, argv)
1617 int argc;
1618 char **argv;
1619 {
1620   register char **clist = 0, **ilist = 0, **zlist = 0;
1621   int badflag = 0;
1622 
1623   register int devgiven = 0;
1624   register char *arg;
1625 
1626   if ((1 << BITSHIFT) != 8 * sizeof(bitchunk_t)) {
1627 	printf("Fsck was compiled with the wrong BITSHIFT!\n");
1628 	exit(FSCK_EXIT_CHECK_FAILED);
1629   }
1630 
1631   sync();
1632   prog = *argv++;
1633   while ((arg = *argv++) != 0)
1634 	if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) {
1635 		    case 'd':	markdirty = 1;	break;
1636 		    case 'p':	preen = repair = automatic = 1; break;
1637 	            case 'y':
1638 		    case 'a':	automatic ^= 1;	break;
1639 		    case 'c':
1640 			clist = getlist(&argv, "inode");
1641 			break;
1642 		    case 'i':
1643 			ilist = getlist(&argv, "inode");
1644 			break;
1645 		    case 'z':
1646 			zlist = getlist(&argv, "zone");
1647 			break;
1648 		    case 'r':	repair ^= 1;	break;
1649 		    case 'l':	listing ^= 1;	break;
1650 		    case 's':	listsuper ^= 1;	break;
1651 		    case 'f':	break;
1652 		    default:
1653 			printf("%s: unknown flag '%s'\n", prog, arg);
1654 			badflag = 1;
1655 		}
1656 	else {
1657 		chkdev(arg, clist, ilist, zlist);
1658 		clist = 0;
1659 		ilist = 0;
1660 		zlist = 0;
1661 		devgiven = 1;
1662 	}
1663   if (!devgiven || badflag) {
1664 	printf("Usage: fsck [-dyfpacilrsz] file\n");
1665 	exit(FSCK_EXIT_USAGE);
1666   }
1667   return(0);
1668 }
1669 
1670 void panic(char *fmt, ...)
1671 {
1672 	fprintf(stderr, "%s\n", fmt);
1673 	exit(1);
1674 }
1675 
1676