source: trunk/minix/commands/simple/fsck1.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

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