00001
00002
00003 #define INODES_PER_BLOCK V2_INODES_PER_BLOCK(block_size)
00004 #define INODE_SIZE ((int) V2_INODE_SIZE)
00005 #define WORDS_PER_BLOCK (block_size / (int) sizeof(bitchunk_t))
00006 #define MAX_ZONES (V2_NR_DZONES+V2_INDIRECTS(block_size)+(long)V2_INDIRECTS(block_size)*V2_INDIRECTS(block_size))
00007 #define NR_DZONE_NUM V2_NR_DZONES
00008 #define NR_INDIRECTS V2_INDIRECTS(block_size)
00009 #define NR_ZONE_NUMS V2_NR_TZONES
00010 #define ZONE_NUM_SIZE V2_ZONE_NUM_SIZE
00011 #define bit_nr bit_t
00012 #define block_nr block_t
00013 #define d_inode d2_inode
00014 #define d_inum d_ino
00015 #define dir_struct struct direct
00016 #define i_mode d2_mode
00017 #define i_nlinks d2_nlinks
00018 #define i_size d2_size
00019 #define i_zone d2_zone
00020 #define zone_nr zone_t
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <sys/types.h>
00039 #include <sys/dir.h>
00040 #include <ctype.h>
00041 #include <errno.h>
00042 #include <fcntl.h>
00043 #include <limits.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <unistd.h>
00047 #include <minix/config.h>
00048 #include <minix/const.h>
00049 #include <minix/type.h>
00050 #include "../../servers/fs/const.h"
00051 #include "../../servers/fs/inode.h"
00052 #include "../../servers/fs/type.h"
00053 #include <minix/fslib.h>
00054 #include <stdio.h>
00055 #include <sys/stat.h>
00056 #include <a.out.h>
00057 #include <tools.h>
00058 #include <dirent.h>
00059
00060 #undef N_DATA
00061
00062 unsigned int fs_version = 2, block_size = 0;
00063
00064 #define BITSHIFT 4
00065
00066 #define MAXPRINT 80
00067 #define CINDIR 128
00068 #define CDIRECT 1
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 #define BITMASK ((1 << BITSHIFT) - 1)
00081 #define WORDOFBIT(b) ((b) >> BITSHIFT)
00082 #define POWEROFBIT(b) (1 << ((int) (b) & BITMASK))
00083 #define setbit(w, b) (w[WORDOFBIT(b)] |= POWEROFBIT(b))
00084 #define clrbit(w, b) (w[WORDOFBIT(b)] &= ~POWEROFBIT(b))
00085 #define bitset(w, b) (w[WORDOFBIT(b)] & POWEROFBIT(b))
00086
00087 #define ZONE_CT 360
00088 #define INODE_CT 95
00089
00090 #include "../../servers/fs/super.h"
00091 static struct super_block sb;
00092
00093 #define STICKY_BIT 01000
00094
00095
00096
00097
00098 #define ztob(z) ((block_nr) (z) << sb.s_log_zone_size)
00099 #define btoa(b) ((long) (b) * block_size)
00100 #define SCALE ((int) ztob(1))
00101 #define FIRST ((zone_nr) sb.s_firstdatazone)
00102
00103
00104 #define N_IMAP (sb.s_imap_blocks)
00105 #define N_ZMAP (sb.s_zmap_blocks)
00106 #define N_ILIST ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
00107 #define N_DATA (sb.s_zones - FIRST)
00108
00109
00110 #define OFFSET_SUPER_BLOCK SUPER_BLOCK_BYTES
00111 #define BLK_IMAP 2
00112 #define BLK_ZMAP (BLK_IMAP + N_IMAP)
00113 #define BLK_ILIST (BLK_ZMAP + N_ZMAP)
00114 #define BLK_FIRST ztob(FIRST)
00115 #define ZONE_SIZE ((int) ztob(block_size))
00116 #define NLEVEL (NR_ZONE_NUMS - NR_DZONE_NUM + 1)
00117
00118
00119 #define zaddr(z) btoa(ztob(z))
00120 #define cinoaddr(i) ((long) (i - 1) * INODE_SIZE + (long) btoa(BLK_ILIST))
00121 #define INDCHUNK ((int) (CINDIR * ZONE_NUM_SIZE))
00122 #define DIRCHUNK ((int) (CDIRECT * DIR_ENTRY_SIZE))
00123
00124 char *prog, *fsck_device;
00125 int firstcnterr;
00126 bitchunk_t *imap, *spec_imap;
00127 bitchunk_t *zmap, *spec_zmap;
00128 bitchunk_t *dirmap;
00129 char *rwbuf;
00130 block_nr thisblk;
00131 char *nullbuf;
00132 nlink_t *count;
00133 int changed;
00134 struct stack {
00135 dir_struct *st_dir;
00136 struct stack *st_next;
00137 char st_presence;
00138 } *ftop;
00139
00140 int dev;
00141
00142 #define DOT 1
00143 #define DOTDOT 2
00144
00145
00146 int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode;
00147 int npipe, nsyml, ztype[NLEVEL];
00148 long nfreezone;
00149
00150 int repair, automatic, listing, listsuper;
00151 int firstlist;
00152 unsigned part_offset;
00153 char answer[] = "Answer questions with y or n. Then hit RETURN";
00154
00155 _PROTOTYPE(int main, (int argc, char **argv));
00156 _PROTOTYPE(void initvars, (void));
00157 _PROTOTYPE(void fatal, (char *s));
00158 _PROTOTYPE(int eoln, (int c));
00159 _PROTOTYPE(int yes, (char *question));
00160 _PROTOTYPE(int atoo, (char *s));
00161 _PROTOTYPE(int input, (char *buf, int size));
00162 _PROTOTYPE(char *alloc, (unsigned nelem, unsigned elsize));
00163 _PROTOTYPE(void printname, (char *s));
00164 _PROTOTYPE(void printrec, (struct stack *sp));
00165 _PROTOTYPE(void printpath, (int mode, int nlcr));
00166 _PROTOTYPE(void devopen, (void));
00167 _PROTOTYPE(void devclose, (void));
00168 _PROTOTYPE(void devio, (block_nr bno, int dir));
00169 _PROTOTYPE(void devread, (long offset, char *buf, int size));
00170 _PROTOTYPE(void devwrite, (long offset, char *buf, int size));
00171 _PROTOTYPE(void pr, (char *fmt, int cnt, char *s, char *p));
00172 _PROTOTYPE(void lpr, (char *fmt, long cnt, char *s, char *p));
00173 _PROTOTYPE(bit_nr getnumber, (char *s));
00174 _PROTOTYPE(char **getlist, (char ***argv, char *type));
00175 _PROTOTYPE(void lsuper, (void));
00176 _PROTOTYPE(void getsuper, (void));
00177 _PROTOTYPE(void chksuper, (void));
00178 _PROTOTYPE(void lsi, (char **clist));
00179 _PROTOTYPE(bitchunk_t *allocbitmap, (int nblk));
00180 _PROTOTYPE(void loadbitmap, (bitchunk_t *bitmap, block_nr bno, int nblk));
00181 _PROTOTYPE(void dumpbitmap, (bitchunk_t *bitmap, block_nr bno, int nblk));
00182 _PROTOTYPE(void fillbitmap, (bitchunk_t *bitmap, bit_nr lwb, bit_nr upb, char **list));
00183 _PROTOTYPE(void freebitmap, (bitchunk_t *p));
00184 _PROTOTYPE(void getbitmaps, (void));
00185 _PROTOTYPE(void putbitmaps, (void));
00186 _PROTOTYPE(void chkword, (unsigned w1, unsigned w2, bit_nr bit, char *type, int *n, int *report, bit_t));
00187 _PROTOTYPE(void chkmap, (bitchunk_t *cmap, bitchunk_t *dmap, bit_nr bit, block_nr blkno, int nblk, char *type));
00188 _PROTOTYPE(void chkilist, (void));
00189 _PROTOTYPE(void getcount, (void));
00190 _PROTOTYPE(void counterror, (Ino_t ino));
00191 _PROTOTYPE(void chkcount, (void));
00192 _PROTOTYPE(void freecount, (void));
00193 _PROTOTYPE(void printperm, (mode_t mode, int shift, int special, int overlay));
00194 _PROTOTYPE(void list, (Ino_t ino, d_inode *ip));
00195 _PROTOTYPE(int Remove, (dir_struct *dp));
00196 _PROTOTYPE(void make_printable_name, (char *dst, char *src, int n));
00197 _PROTOTYPE(int chkdots, (Ino_t ino, off_t pos, dir_struct *dp, Ino_t exp));
00198 _PROTOTYPE(int chkname, (Ino_t ino, dir_struct *dp));
00199 _PROTOTYPE(int chkentry, (Ino_t ino, off_t pos, dir_struct *dp));
00200 _PROTOTYPE(int chkdirzone, (Ino_t ino, d_inode *ip, off_t pos, zone_nr zno));
00201 _PROTOTYPE(int chksymlinkzone, (Ino_t ino, d_inode *ip, off_t pos,
00202 zone_nr zno));
00203 _PROTOTYPE(void errzone, (char *mess, zone_nr zno, int level, off_t pos));
00204 _PROTOTYPE(int markzone, (zone_nr zno, int level, off_t pos));
00205 _PROTOTYPE(int chkindzone, (Ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level));
00206 _PROTOTYPE(off_t jump, (int level));
00207 _PROTOTYPE(int zonechk, (Ino_t ino, d_inode *ip, off_t *pos, zone_nr zno, int level));
00208 _PROTOTYPE(int chkzones, (Ino_t ino, d_inode *ip, off_t *pos, zone_nr *zlist, int len, int level));
00209 _PROTOTYPE(int chkfile, (Ino_t ino, d_inode *ip));
00210 _PROTOTYPE(int chkdirectory, (Ino_t ino, d_inode *ip));
00211 _PROTOTYPE(int chklink, (Ino_t ino, d_inode *ip));
00212 _PROTOTYPE(int chkspecial, (Ino_t ino, d_inode *ip));
00213 _PROTOTYPE(int chkmode, (Ino_t ino, d_inode *ip));
00214 _PROTOTYPE(int chkinode, (Ino_t ino, d_inode *ip));
00215 _PROTOTYPE(int descendtree, (dir_struct *dp));
00216 _PROTOTYPE(void chktree, (void));
00217 _PROTOTYPE(void printtotal, (void));
00218 _PROTOTYPE(void chkdev, (char *f, char **clist, char **ilist, char **zlist));
00219
00220
00221 void initvars()
00222 {
00223 register level;
00224
00225 nregular = ndirectory = nblkspec = ncharspec = nbadinode = npipe = nsyml = 0;
00226 for (level = 0; level < NLEVEL; level++) ztype[level] = 0;
00227 changed = 0;
00228 thisblk = NO_BLOCK;
00229 firstlist = 1;
00230 firstcnterr = 1;
00231 }
00232
00233
00234 void fatal(s)
00235 char *s;
00236 {
00237 printf("%s\nfatal\n", s);
00238 exit(-1);
00239 }
00240
00241
00242 int eoln(c)
00243 int c;
00244 {
00245 return(c == EOF || c == '\n' || c == '\r');
00246 }
00247
00248
00249 int yes(question)
00250 char *question;
00251 {
00252 register int c, answerchar;
00253 static int note = 0;
00254
00255 if (!repair) {
00256 printf("\n");
00257 return(0);
00258 }
00259 printf("%s? ", question);
00260 if(!note) { printf("(y=yes, n=no, q=quit, A=for yes to all) "); note = 1; }
00261 if (automatic) {
00262 printf("yes\n");
00263 return(1);
00264 }
00265 fflush(stdout);
00266 if ((c = answerchar = getchar()) == 'q' || c == 'Q') exit(1);
00267 if(c == 'A') { automatic = 1; c = 'y'; }
00268 while (!eoln(c)) c = getchar();
00269 return !(answerchar == 'n' || answerchar == 'N');
00270 }
00271
00272
00273 int atoo(s)
00274 register char *s;
00275 {
00276 register int n = 0;
00277
00278 while ('0' <= *s && *s < '8') {
00279 n <<= 3;
00280 n += *s++ - '0';
00281 }
00282 return n;
00283 }
00284
00285
00286 int input(buf, size)
00287 char *buf;
00288 int size;
00289 {
00290 register char *p = buf;
00291
00292 printf("\n");
00293 if (repair) {
00294 printf("--> ");
00295 fflush(stdout);
00296 while (--size) {
00297 *p = getchar();
00298 if (eoln(*p)) {
00299 *p = 0;
00300 return(p > buf);
00301 }
00302 p++;
00303 }
00304 *p = 0;
00305 while (!eoln(getchar()));
00306 return(1);
00307 }
00308 return(0);
00309 }
00310
00311
00312 char *alloc(nelem, elsize)
00313 unsigned nelem, elsize;
00314 {
00315 char *p;
00316
00317 if ((p = (char *)malloc((size_t)nelem * elsize)) == 0) {
00318 fprintf(stderr, "Tried to allocate %dkB\n",
00319 nelem*elsize/1024);
00320 fatal("out of memory");
00321 }
00322 memset((void *) p, 0, (size_t)nelem * elsize);
00323 return(p);
00324 }
00325
00326
00327 void printname(s)
00328 char *s;
00329 {
00330 register n = NAME_MAX;
00331 int c;
00332
00333 do {
00334 if ((c = *s) == 0) break;
00335 if (!isprint(c)) c = '?';
00336 putchar(c);
00337 s++;
00338 } while (--n);
00339 }
00340
00341
00342
00343
00344 void printrec(sp)
00345 struct stack *sp;
00346 {
00347 if (sp->st_next != 0) {
00348 printrec(sp->st_next);
00349 putchar('/');
00350 printname(sp->st_dir->d_name);
00351 }
00352 }
00353
00354
00355 void printpath(mode, nlcr)
00356 int mode;
00357 int nlcr;
00358 {
00359 if (ftop->st_next == 0)
00360 putchar('/');
00361 else
00362 printrec(ftop);
00363 switch (mode) {
00364 case 1:
00365 printf(" (ino = %u, ", ftop->st_dir->d_inum);
00366 break;
00367 case 2:
00368 printf(" (ino = %u)", ftop->st_dir->d_inum);
00369 break;
00370 }
00371 if (nlcr) printf("\n");
00372 }
00373
00374
00375 void devopen()
00376 {
00377 if ((dev = open(fsck_device, repair ? O_RDWR : O_RDONLY)) < 0) {
00378 perror(fsck_device);
00379 fatal("couldn't open device to fsck");
00380 }
00381 }
00382
00383
00384 void devclose()
00385 {
00386 if (close(dev) != 0) {
00387 perror("close");
00388 fatal("");
00389 }
00390 }
00391
00392
00393 void devio(bno, dir)
00394 block_nr bno;
00395 int dir;
00396 {
00397 if(!block_size) fatal("devio() with unknown block size");
00398 if (dir == READING && bno == thisblk) return;
00399 thisblk = bno;
00400
00401 #if 0
00402 printf("%s at block %5d\n", dir == READING ? "reading " : "writing", bno);
00403 #endif
00404 lseek(dev, (off_t) btoa(bno), SEEK_SET);
00405 if (dir == READING) {
00406 if (read(dev, rwbuf, block_size) == block_size)
00407 return;
00408 } else {
00409 if (write(dev, rwbuf, block_size) == block_size)
00410 return;
00411 }
00412
00413 printf("%s: can't %s block %ld (error = 0x%x)\n", prog,
00414 dir == READING ? "read" : "write", (long) bno, errno);
00415 if (dir == READING) {
00416 printf("Continuing with a zero-filled block.\n");
00417 memset(rwbuf, 0, block_size);
00418 return;
00419 }
00420 fatal("");
00421 }
00422
00423
00424 void devread(offset, buf, size)
00425 long offset;
00426 char *buf;
00427 int size;
00428 {
00429 if(!block_size) fatal("devread() with unknown block size");
00430 devio((block_nr) (offset / block_size), READING);
00431 memmove(buf, &rwbuf[(int) (offset % block_size)], (size_t)size);
00432 }
00433
00434
00435 void devwrite(offset, buf, size)
00436 long offset;
00437 char *buf;
00438 int size;
00439 {
00440 if(!block_size) fatal("devwrite() with unknown block size");
00441 if (!repair) fatal("internal error (devwrite)");
00442 if (size != block_size) devio((block_nr) (offset / block_size), READING);
00443 memmove(&rwbuf[(int) (offset % block_size)], buf, (size_t)size);
00444 devio((block_nr) (offset / block_size), WRITING);
00445 changed = 1;
00446 }
00447
00448
00449 void pr(fmt, cnt, s, p)
00450 char *fmt, *s, *p;
00451 int cnt;
00452 {
00453 printf(fmt, cnt, cnt == 1 ? s : p);
00454 }
00455
00456
00457 void lpr(fmt, cnt, s, p)
00458 char *fmt, *s, *p;
00459 long cnt;
00460 {
00461 printf(fmt, cnt, cnt == 1 ? s : p);
00462 }
00463
00464
00465 bit_nr getnumber(s)
00466 register char *s;
00467 {
00468 register bit_nr n = 0;
00469
00470 if (s == NULL)
00471 return NO_BIT;
00472 while (isdigit(*s))
00473 n = (n << 1) + (n << 3) + *s++ - '0';
00474 return (*s == '\0') ? n : NO_BIT;
00475 }
00476
00477
00478 char **getlist(argv, type)
00479 char ***argv, *type;
00480 {
00481 register char **list = *argv;
00482 register empty = 1;
00483
00484 while (getnumber(**argv) != NO_BIT) {
00485 (*argv)++;
00486 empty = 0;
00487 }
00488 if (empty) {
00489 printf("warning: no %s numbers given\n", type);
00490 return(NULL);
00491 }
00492 return(list);
00493 }
00494
00495
00496
00497
00498 void lsuper()
00499 {
00500 char buf[80];
00501
00502 do {
00503
00504 printf("ninodes = %u", sb.s_ninodes);
00505 if (input(buf, 80)) sb.s_ninodes = atol(buf);
00506 printf("nzones = %ld", sb.s_zones);
00507 if (input(buf, 80)) sb.s_zones = atol(buf);
00508 printf("imap_blocks = %u", sb.s_imap_blocks);
00509 if (input(buf, 80)) sb.s_imap_blocks = atol(buf);
00510 printf("zmap_blocks = %u", sb.s_zmap_blocks);
00511 if (input(buf, 80)) sb.s_zmap_blocks = atol(buf);
00512 printf("firstdatazone = %u", sb.s_firstdatazone);
00513 if (input(buf, 80)) sb.s_firstdatazone = atol(buf);
00514 printf("log_zone_size = %u", sb.s_log_zone_size);
00515 if (input(buf, 80)) sb.s_log_zone_size = atol(buf);
00516 printf("maxsize = %ld", sb.s_max_size);
00517 if (input(buf, 80)) sb.s_max_size = atol(buf);
00518 printf("block size = %ld", sb.s_block_size);
00519 if (input(buf, 80)) sb.s_block_size = atol(buf);
00520 if (yes("ok now")) {
00521 devwrite(OFFSET_SUPER_BLOCK, (char *) &sb, sizeof(sb));
00522 return;
00523 }
00524 } while (yes("Do you want to try again"));
00525 if (repair) exit(0);
00526 }
00527
00528
00529 void getsuper()
00530 {
00531 if(lseek(dev, OFFSET_SUPER_BLOCK, SEEK_SET) < 0) {
00532 perror("lseek");
00533 fatal("couldn't seek to super block.");
00534 }
00535 if(read(dev, &sb, sizeof(sb)) != sizeof(sb)) {
00536 fatal("couldn't read super block.");
00537 }
00538 if (listsuper) lsuper();
00539 if (sb.s_magic == SUPER_MAGIC) fatal("Cannot handle V1 file systems");
00540 if (sb.s_magic == SUPER_V2) {
00541 fs_version = 2;
00542 block_size = 8192;
00543 } else if(sb.s_magic == SUPER_V3) {
00544 fs_version = 3;
00545 block_size = sb.s_block_size;
00546 } else {
00547 fatal("bad magic number in super block");
00548 }
00549 if (sb.s_ninodes <= 0) fatal("no inodes");
00550 if (sb.s_zones <= 0) fatal("no zones");
00551 if (sb.s_imap_blocks <= 0) fatal("no imap");
00552 if (sb.s_zmap_blocks <= 0) fatal("no zmap");
00553 if (sb.s_firstdatazone <= 4) fatal("first data zone too small");
00554 if (sb.s_log_zone_size < 0) fatal("zone size < block size");
00555 if (sb.s_max_size <= 0) fatal("max. file size <= 0");
00556
00557 }
00558
00559
00560 void chksuper()
00561 {
00562 register n;
00563 register off_t maxsize;
00564
00565 n = bitmapsize((bit_t) sb.s_ninodes + 1, block_size);
00566 if (sb.s_magic != SUPER_V2 && sb.s_magic != SUPER_V3)
00567 fatal("bad magic number in super block");
00568 if (sb.s_imap_blocks < n) {
00569 printf("need %d bocks for inode bitmap; only have %d\n",
00570 n, sb.s_imap_blocks);
00571 fatal("too few imap blocks");
00572 }
00573 if (sb.s_imap_blocks != n) {
00574 pr("warning: expected %d imap_block%s", n, "", "s");
00575 printf(" instead of %d\n", sb.s_imap_blocks);
00576 }
00577 n = bitmapsize((bit_t) sb.s_zones, block_size);
00578 if (sb.s_zmap_blocks < n) fatal("too few zmap blocks");
00579 if (sb.s_zmap_blocks != n) {
00580 pr("warning: expected %d zmap_block%s", n, "", "s");
00581 printf(" instead of %d\n", sb.s_zmap_blocks);
00582 }
00583 if (sb.s_firstdatazone >= sb.s_zones)
00584 fatal("first data zone too large");
00585 if (sb.s_log_zone_size >= 8 * sizeof(block_nr))
00586 fatal("log_zone_size too large");
00587 if (sb.s_log_zone_size > 8) printf("warning: large log_zone_size (%d)\n",
00588 sb.s_log_zone_size);
00589 n = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size;
00590 if (sb.s_firstdatazone < n) fatal("first data zone too small");
00591 if (sb.s_firstdatazone != n) {
00592 printf("warning: expected first data zone to be %d ", n);
00593 printf("instead of %u\n", sb.s_firstdatazone);
00594 }
00595 maxsize = MAX_FILE_POS;
00596 if (((maxsize - 1) >> sb.s_log_zone_size) / block_size >= MAX_ZONES)
00597 maxsize = ((long) MAX_ZONES * block_size) << sb.s_log_zone_size;
00598 if (sb.s_max_size != maxsize) {
00599 printf("warning: expected max size to be %ld ", maxsize);
00600 printf("instead of %ld\n", sb.s_max_size);
00601 }
00602 }
00603
00604 int inoaddr(int inn)
00605 {
00606 int a;
00607 a = cinoaddr(inn);
00608 return a;
00609 }
00610
00611
00612
00613
00614 void lsi(clist)
00615 char **clist;
00616 {
00617 register bit_nr bit;
00618 register ino_t ino;
00619 d_inode inode, *ip = &inode;
00620 char buf[80];
00621
00622 if (clist == 0) return;
00623 while ((bit = getnumber(*clist++)) != NO_BIT) {
00624 setbit(spec_imap, bit);
00625 ino = bit;
00626 do {
00627 devread(inoaddr(ino), (char *) ip, INODE_SIZE);
00628 printf("inode %u:\n", ino);
00629 printf(" mode = %6o", ip->i_mode);
00630 if (input(buf, 80)) ip->i_mode = atoo(buf);
00631 printf(" nlinks = %6u", ip->i_nlinks);
00632 if (input(buf, 80)) ip->i_nlinks = atol(buf);
00633 printf(" size = %6ld", ip->i_size);
00634 if (input(buf, 80)) ip->i_size = atol(buf);
00635 if (yes("Write this back")) {
00636 devwrite(inoaddr(ino), (char *) ip, INODE_SIZE);
00637 break;
00638 }
00639 } while (yes("Do you want to change it again"));
00640 }
00641 }
00642
00643
00644 bitchunk_t *allocbitmap(nblk)
00645 int nblk;
00646 {
00647 register bitchunk_t *bitmap;
00648
00649 bitmap = (bitchunk_t *) alloc((unsigned) nblk, block_size);
00650 *bitmap |= 1;
00651 return(bitmap);
00652 }
00653
00654
00655 void loadbitmap(bitmap, bno, nblk)
00656 bitchunk_t *bitmap;
00657 block_nr bno;
00658 int nblk;
00659 {
00660 register i;
00661 register bitchunk_t *p;
00662
00663 p = bitmap;
00664 for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
00665 devread(btoa(bno), (char *) p, block_size);
00666 *bitmap |= 1;
00667 }
00668
00669
00670 void dumpbitmap(bitmap, bno, nblk)
00671 bitchunk_t *bitmap;
00672 block_nr bno;
00673 int nblk;
00674 {
00675 register i;
00676 register bitchunk_t *p = bitmap;
00677
00678 for (i = 0; i < nblk; i++, bno++, p += WORDS_PER_BLOCK)
00679 devwrite(btoa(bno), (char *) p, block_size);
00680 }
00681
00682
00683 void fillbitmap(bitmap, lwb, upb, list)
00684 bitchunk_t *bitmap;
00685 bit_nr lwb, upb;
00686 char **list;
00687 {
00688 register bit_nr bit;
00689
00690 if (list == 0) return;
00691 while ((bit = getnumber(*list++)) != NO_BIT)
00692 if (bit < lwb || bit >= upb) {
00693 if (bitmap == spec_imap)
00694 printf("inode number %ld ", bit);
00695 else
00696 printf("zone number %ld ", bit);
00697 printf("out of range (ignored)\n");
00698 } else
00699 setbit(bitmap, bit - lwb + 1);
00700 }
00701
00702
00703 void freebitmap(p)
00704 bitchunk_t *p;
00705 {
00706 free((char *) p);
00707 }
00708
00709
00710 void getbitmaps()
00711 {
00712 imap = allocbitmap(N_IMAP);
00713 zmap = allocbitmap(N_ZMAP);
00714 spec_imap = allocbitmap(N_IMAP);
00715 spec_zmap = allocbitmap(N_ZMAP);
00716 dirmap = allocbitmap(N_IMAP);
00717 }
00718
00719
00720 void putbitmaps()
00721 {
00722 freebitmap(imap);
00723 freebitmap(zmap);
00724 freebitmap(spec_imap);
00725 freebitmap(spec_zmap);
00726 freebitmap(dirmap);
00727 }
00728
00729
00730
00731
00732 void chkword(w1, w2, bit, type, n, report, phys)
00733 unsigned w1, w2;
00734 char *type;
00735 bit_nr bit;
00736 int *n, *report;
00737 bit_nr phys;
00738 {
00739 for (; (w1 | w2); w1 >>= 1, w2 >>= 1, bit++, phys++)
00740 if ((w1 ^ w2) & 1 && ++(*n) % MAXPRINT == 0 && *report &&
00741 (!repair || automatic || yes("stop this listing")))
00742 *report = 0;
00743 else if (*report)
00744 if ((w1 & 1) && !(w2 & 1))
00745 printf("%s %ld (%ld) is missing\n", type, bit, phys);
00746 else if (!(w1 & 1) && (w2 & 1))
00747 printf("%s %ld (%ld) is not free\n", type, bit, phys);
00748 }
00749
00750
00751
00752
00753 void chkmap(cmap, dmap, bit, blkno, nblk, type)
00754 bitchunk_t *cmap, *dmap;
00755 bit_nr bit;
00756 block_nr blkno;
00757 int nblk;
00758 char *type;
00759 {
00760 register bitchunk_t *p = dmap, *q = cmap;
00761 int report = 1, nerr = 0;
00762 int w = nblk * WORDS_PER_BLOCK;
00763 bit_nr phys = 0;
00764
00765 printf("Checking %s map\n", type);
00766 loadbitmap(dmap, blkno, nblk);
00767 do {
00768 if (*p != *q) chkword(*p, *q, bit, type, &nerr, &report, phys);
00769 p++;
00770 q++;
00771 bit += 8 * sizeof(bitchunk_t);
00772 phys += 8 * sizeof(bitchunk_t);
00773 } while (--w > 0);
00774
00775 if ((!repair || automatic) && !report) printf("etc. ");
00776 if (nerr > MAXPRINT || nerr > 10) printf("%d errors found. ", nerr);
00777 if (nerr != 0 && yes("install a new map")) dumpbitmap(cmap, blkno, nblk);
00778 if (nerr > 0) printf("\n");
00779 }
00780
00781
00782 void chkilist()
00783 {
00784 register ino_t ino = 1;
00785 mode_t mode;
00786
00787 printf("Checking inode list\n");
00788 do
00789 if (!bitset(imap, (bit_nr) ino)) {
00790 devread(inoaddr(ino), (char *) &mode, sizeof(mode));
00791 if (mode != I_NOT_ALLOC) {
00792 printf("mode inode %u not cleared", ino);
00793 if (yes(". clear")) devwrite(inoaddr(ino), nullbuf,
00794 INODE_SIZE);
00795 }
00796 }
00797 while (++ino <= sb.s_ninodes && ino != 0);
00798 printf("\n");
00799 }
00800
00801
00802 void getcount()
00803 {
00804 count = (nlink_t *) alloc((unsigned) (sb.s_ninodes + 1), sizeof(nlink_t));
00805 }
00806
00807
00808 void counterror(ino)
00809 ino_t ino;
00810 {
00811 d_inode inode;
00812
00813 if (firstcnterr) {
00814 printf("INODE NLINK COUNT\n");
00815 firstcnterr = 0;
00816 }
00817 devread(inoaddr(ino), (char *) &inode, INODE_SIZE);
00818 count[ino] += inode.i_nlinks;
00819 printf("%5u %5u %5u", ino, (unsigned) inode.i_nlinks, count[ino]);
00820 if (yes(" adjust")) {
00821 if ((inode.i_nlinks = count[ino]) == 0) {
00822 fatal("internal error (counterror)");
00823 inode.i_mode = I_NOT_ALLOC;
00824 clrbit(imap, (bit_nr) ino);
00825 }
00826 devwrite(inoaddr(ino), (char *) &inode, INODE_SIZE);
00827 }
00828 }
00829
00830
00831
00832
00833
00834
00835
00836
00837 void chkcount()
00838 {
00839 register ino_t ino;
00840
00841 for (ino = 1; ino <= sb.s_ninodes && ino != 0; ino++)
00842 if (count[ino] != 0) counterror(ino);
00843 if (!firstcnterr) printf("\n");
00844 }
00845
00846
00847 void freecount()
00848 {
00849 free((char *) count);
00850 }
00851
00852
00853 void printperm(mode_t mode, int shift, int special, int overlay)
00854 {
00855 if (mode >> shift & R_BIT)
00856 putchar('r');
00857 else
00858 putchar('-');
00859 if (mode >> shift & W_BIT)
00860 putchar('w');
00861 else
00862 putchar('-');
00863 if (mode & special)
00864 putchar(overlay);
00865 else
00866 if (mode >> shift & X_BIT)
00867 putchar('x');
00868 else
00869 putchar('-');
00870 }
00871
00872
00873 void list(ino, ip)
00874 ino_t ino;
00875 d_inode *ip;
00876 {
00877 if (firstlist) {
00878 firstlist = 0;
00879 printf(" inode permission link size name\n");
00880 }
00881 printf("%6u ", ino);
00882 switch (ip->i_mode & I_TYPE) {
00883 case I_REGULAR: putchar('-'); break;
00884 case I_DIRECTORY: putchar('d'); break;
00885 case I_CHAR_SPECIAL: putchar('c'); break;
00886 case I_BLOCK_SPECIAL: putchar('b'); break;
00887 case I_NAMED_PIPE: putchar('p'); break;
00888 #ifdef I_SYMBOLIC_LINK
00889 case I_SYMBOLIC_LINK: putchar('l'); break;
00890 #endif
00891 default: putchar('?');
00892 }
00893 printperm(ip->i_mode, 6, I_SET_UID_BIT, 's');
00894 printperm(ip->i_mode, 3, I_SET_GID_BIT, 's');
00895 printperm(ip->i_mode, 0, STICKY_BIT, 't');
00896 printf(" %3u ", ip->i_nlinks);
00897 switch (ip->i_mode & I_TYPE) {
00898 case I_CHAR_SPECIAL:
00899 case I_BLOCK_SPECIAL:
00900 printf(" %2x,%2x ", (dev_t) ip->i_zone[0] >> MAJOR & 0xFF,
00901 (dev_t) ip->i_zone[0] >> MINOR & 0xFF);
00902 break;
00903 default: printf("%7ld ", ip->i_size);
00904 }
00905 printpath(0, 1);
00906 }
00907
00908
00909
00910
00911
00912 int Remove(dp)
00913 dir_struct *dp;
00914 {
00915 setbit(spec_imap, (bit_nr) dp->d_inum);
00916 if (yes(". remove entry")) {
00917 count[dp->d_inum]--;
00918 memset((void *) dp, 0, sizeof(dir_struct));
00919 return(1);
00920 }
00921 return(0);
00922 }
00923
00924
00925 void make_printable_name(dst, src, n)
00926 register char *dst;
00927 register char *src;
00928 register int n;
00929 {
00930 register int c;
00931
00932 while (--n >= 0 && (c = *src++) != '\0') {
00933 if (isprint(c) && c != '\\')
00934 *dst++ = c;
00935 else {
00936 *dst++ = '\\';
00937 switch (c) {
00938 case '\\':
00939 *dst++ = '\\'; break;
00940 case '\b':
00941 *dst++ = 'b'; break;
00942 case '\f':
00943 *dst++ = 'f'; break;
00944 case '\n':
00945 *dst++ = 'n'; break;
00946 case '\r':
00947 *dst++ = 'r'; break;
00948 case '\t':
00949 *dst++ = 't'; break;
00950 default:
00951 *dst++ = '0' + ((c >> 6) & 03);
00952 *dst++ = '0' + ((c >> 3) & 07);
00953 *dst++ = '0' + (c & 07);
00954 }
00955 }
00956 }
00957 *dst = '\0';
00958 }
00959
00960
00961 int chkdots(ino, pos, dp, exp)
00962 ino_t ino, exp;
00963 off_t pos;
00964 dir_struct *dp;
00965 {
00966 char printable_name[4 * NAME_MAX + 1];
00967
00968 if (dp->d_inum != exp) {
00969 make_printable_name(printable_name, dp->d_name, sizeof(dp->d_name));
00970 printf("bad %s in ", printable_name);
00971 printpath(1, 0);
00972 printf("%s is linked to %u ", printable_name, dp->d_inum);
00973 printf("instead of %u)", exp);
00974 setbit(spec_imap, (bit_nr) ino);
00975 setbit(spec_imap, (bit_nr) dp->d_inum);
00976 setbit(spec_imap, (bit_nr) exp);
00977 if (yes(". repair")) {
00978 count[dp->d_inum]--;
00979 dp->d_inum = exp;
00980 count[exp]++;
00981 return(0);
00982 }
00983 } else if (pos != (dp->d_name[1] ? DIR_ENTRY_SIZE : 0)) {
00984 make_printable_name(printable_name, dp->d_name, sizeof(dp->d_name));
00985 printf("warning: %s has offset %ld in ", printable_name, pos);
00986 printpath(1, 0);
00987 printf("%s is linked to %u)\n", printable_name, dp->d_inum);
00988 setbit(spec_imap, (bit_nr) ino);
00989 setbit(spec_imap, (bit_nr) dp->d_inum);
00990 setbit(spec_imap, (bit_nr) exp);
00991 }
00992 return(1);
00993 }
00994
00995
00996 int chkname(ino, dp)
00997 ino_t ino;
00998 dir_struct *dp;
00999 {
01000 register n = NAME_MAX + 1;
01001 register char *p = dp->d_name;
01002
01003 if (*p == '\0') {
01004 printf("null name found in ");
01005 printpath(0, 0);
01006 setbit(spec_imap, (bit_nr) ino);
01007 if (Remove(dp)) return(0);
01008 }
01009 while (*p != '\0' && --n != 0)
01010 if (*p++ == '/') {
01011 printf("found a '/' in entry of directory ");
01012 printpath(1, 0);
01013 setbit(spec_imap, (bit_nr) ino);
01014 printf("entry = '");
01015 printname(dp->d_name);
01016 printf("')");
01017 if (Remove(dp)) return(0);
01018 break;
01019 }
01020 return(1);
01021 }
01022
01023
01024
01025
01026 int chkentry(ino, pos, dp)
01027 ino_t ino;
01028 off_t pos;
01029 dir_struct *dp;
01030 {
01031 if (dp->d_inum < ROOT_INODE || dp->d_inum > sb.s_ninodes) {
01032 printf("bad inode found in directory ");
01033 printpath(1, 0);
01034 printf("ino found = %u, ", dp->d_inum);
01035 printf("name = '");
01036 printname(dp->d_name);
01037 printf("')");
01038 if (yes(". remove entry")) {
01039 memset((void *) dp, 0, sizeof(dir_struct));
01040 return(0);
01041 }
01042 return(1);
01043 }
01044 if ((unsigned) count[dp->d_inum] == SHRT_MAX) {
01045 printf("too many links to ino %u\n", dp->d_inum);
01046 printf("discovered at entry '");
01047 printname(dp->d_name);
01048 printf("' in directory ");
01049 printpath(0, 1);
01050 if (Remove(dp)) return(0);
01051 }
01052 count[dp->d_inum]++;
01053 if (strcmp(dp->d_name, ".") == 0) {
01054 ftop->st_presence |= DOT;
01055 return(chkdots(ino, pos, dp, ino));
01056 }
01057 if (strcmp(dp->d_name, "..") == 0) {
01058 ftop->st_presence |= DOTDOT;
01059 return(chkdots(ino, pos, dp, ino == ROOT_INODE ? ino :
01060 ftop->st_next->st_dir->d_inum));
01061 }
01062 if (!chkname(ino, dp)) return(0);
01063 if (bitset(dirmap, (bit_nr) dp->d_inum)) {
01064 printf("link to directory discovered in ");
01065 printpath(1, 0);
01066 printf("name = '");
01067 printname(dp->d_name);
01068 printf("', dir ino = %u)", dp->d_inum);
01069 return !Remove(dp);
01070 }
01071 return(descendtree(dp));
01072 }
01073
01074
01075
01076
01077 int chkdirzone(ino, ip, pos, zno)
01078 ino_t ino;
01079 d_inode *ip;
01080 off_t pos;
01081 zone_nr zno;
01082 {
01083 dir_struct dirblk[CDIRECT];
01084 register dir_struct *dp;
01085 register n, dirty;
01086 register long offset = zaddr(zno);
01087 register off_t size = 0;
01088 n = SCALE * (NR_DIR_ENTRIES(block_size) / CDIRECT);
01089
01090 do {
01091 devread(offset, (char *) dirblk, DIRCHUNK);
01092 dirty = 0;
01093 for (dp = dirblk; dp < &dirblk[CDIRECT]; dp++) {
01094 if (dp->d_inum != NO_ENTRY && !chkentry(ino, pos, dp))
01095 dirty = 1;
01096 pos += DIR_ENTRY_SIZE;
01097 if (dp->d_inum != NO_ENTRY) size = pos;
01098 }
01099 if (dirty) devwrite(offset, (char *) dirblk, DIRCHUNK);
01100 offset += DIRCHUNK;
01101 n--;
01102 } while (n > 0);
01103
01104 if (size > ip->i_size) {
01105 printf("size not updated of directory ");
01106 printpath(2, 0);
01107 if (yes(". extend")) {
01108 setbit(spec_imap, (bit_nr) ino);
01109 ip->i_size = size;
01110 devwrite(inoaddr(ino), (char *) ip, INODE_SIZE);
01111 }
01112 }
01113 return(1);
01114 }
01115
01116
01117 int chksymlinkzone(ino, ip, pos, zno)
01118 ino_t ino;
01119 d_inode *ip;
01120 off_t pos;
01121 zone_nr zno;
01122 {
01123 long offset;
01124 size_t len;
01125 char target[PATH_MAX+1];
01126
01127 if (ip->i_size > PATH_MAX)
01128 fatal("chksymlinkzone: fsck program inconsistency\n");
01129 offset = zaddr(zno);
01130 devread(offset, target, ip->i_size);
01131 target[ip->i_size]= '\0';
01132 len= strlen(target);
01133 if (len != ip->i_size)
01134 {
01135 printf("bad size in symbolic link (%d instead of %d) ",
01136 ip->i_size, len);
01137 printpath(2, 0);
01138 if (yes(". update")) {
01139 setbit(spec_imap, (bit_nr) ino);
01140 ip->i_size = len;
01141 devwrite(inoaddr(ino), (char *) ip, INODE_SIZE);
01142 }
01143 }
01144 return 1;
01145 }
01146
01147
01148 void errzone(mess, zno, level, pos)
01149 char *mess;
01150 zone_nr zno;
01151 int level;
01152 off_t pos;
01153 {
01154 printf("%s zone in ", mess);
01155 printpath(1, 0);
01156 printf("zno = %ld, type = ", zno);
01157 switch (level) {
01158 case 0: printf("DATA"); break;
01159 case 1: printf("SINGLE INDIRECT"); break;
01160 case 2: printf("DOUBLE INDIRECT"); break;
01161 default: printf("VERY INDIRECT");
01162 }
01163 printf(", pos = %ld)\n", pos);
01164 }
01165
01166
01167
01168
01169 int markzone(zno, level, pos)
01170 zone_nr zno;
01171 int level;
01172 off_t pos;
01173 {
01174 register bit_nr bit = (bit_nr) zno - FIRST + 1;
01175
01176 ztype[level]++;
01177 if (zno < FIRST || zno >= sb.s_zones) {
01178 errzone("out-of-range", zno, level, pos);
01179 return(0);
01180 }
01181 if (bitset(zmap, bit)) {
01182 setbit(spec_zmap, bit);
01183 errzone("duplicate", zno, level, pos);
01184 return(0);
01185 }
01186 nfreezone--;
01187 if (bitset(spec_zmap, bit)) errzone("found", zno, level, pos);
01188 setbit(zmap, bit);
01189 return(1);
01190 }
01191
01192
01193
01194
01195 int chkindzone(ino, ip, pos, zno, level)
01196 ino_t ino;
01197 d_inode *ip;
01198 off_t *pos;
01199 zone_nr zno;
01200 int level;
01201 {
01202 zone_nr indirect[CINDIR];
01203 register n = NR_INDIRECTS / CINDIR;
01204 register long offset = zaddr(zno);
01205
01206 do {
01207 devread(offset, (char *) indirect, INDCHUNK);
01208 if (!chkzones(ino, ip, pos, indirect, CINDIR, level - 1)) return(0);
01209 offset += INDCHUNK;
01210 } while (--n && *pos < ip->i_size);
01211 return(1);
01212 }
01213
01214
01215
01216
01217 off_t jump(level)
01218 int level;
01219 {
01220 off_t power = ZONE_SIZE;
01221
01222 if (level != 0) do
01223 power *= NR_INDIRECTS;
01224 while (--level);
01225 return(power);
01226 }
01227
01228
01229
01230
01231 int zonechk(ino, ip, pos, zno, level)
01232 ino_t ino;
01233 d_inode *ip;
01234 off_t *pos;
01235 zone_nr zno;
01236 int level;
01237 {
01238 if (level == 0) {
01239 if ((ip->i_mode & I_TYPE) == I_DIRECTORY &&
01240 !chkdirzone(ino, ip, *pos, zno))
01241 return(0);
01242 if ((ip->i_mode & I_TYPE) == I_SYMBOLIC_LINK &&
01243 !chksymlinkzone(ino, ip, *pos, zno))
01244 return(0);
01245 *pos += ZONE_SIZE;
01246 return(1);
01247 } else
01248 return chkindzone(ino, ip, pos, zno, level);
01249 }
01250
01251
01252 int chkzones(ino, ip, pos, zlist, len, level)
01253 ino_t ino;
01254 d_inode *ip;
01255 off_t *pos;
01256 zone_nr *zlist;
01257 int len;
01258 int level;
01259 {
01260 register ok = 1, i;
01261
01262
01263
01264
01265
01266 for (i = 0; i < len ; i++)
01267 if (zlist[i] == NO_ZONE)
01268 *pos += jump(level);
01269 else if (!markzone(zlist[i], level, *pos)) {
01270 *pos += jump(level);
01271 ok = 0;
01272 } else if (!zonechk(ino, ip, pos, zlist[i], level))
01273 ok = 0;
01274 return(ok);
01275 }
01276
01277
01278 int chkfile(ino, ip)
01279 ino_t ino;
01280 d_inode *ip;
01281 {
01282 register ok, i, level;
01283 off_t pos = 0;
01284
01285 ok = chkzones(ino, ip, &pos, &ip->i_zone[0], NR_DZONE_NUM, 0);
01286 for (i = NR_DZONE_NUM, level = 1; i < NR_ZONE_NUMS; i++, level++)
01287 ok &= chkzones(ino, ip, &pos, &ip->i_zone[i], 1, level);
01288 return(ok);
01289 }
01290
01291
01292 int chkdirectory(ino, ip)
01293 ino_t ino;
01294 d_inode *ip;
01295 {
01296 register ok;
01297
01298 setbit(dirmap, (bit_nr) ino);
01299 ok = chkfile(ino, ip);
01300 if (!(ftop->st_presence & DOT)) {
01301 printf(". missing in ");
01302 printpath(2, 1);
01303 ok = 0;
01304 }
01305 if (!(ftop->st_presence & DOTDOT)) {
01306 printf(".. missing in ");
01307 printpath(2, 1);
01308 ok = 0;
01309 }
01310 return(ok);
01311 }
01312
01313 #ifdef I_SYMBOLIC_LINK
01314
01315
01316 int chklink(ino, ip)
01317 ino_t ino;
01318 d_inode *ip;
01319 {
01320 int ok;
01321
01322 ok = chkfile(ino, ip);
01323 if (ip->i_size <= 0 || ip->i_size > block_size) {
01324 if (ip->i_size == 0)
01325 printf("empty symbolic link ");
01326 else
01327 printf("symbolic link too large (size %ld) ", ip->i_size);
01328 printpath(2, 1);
01329 ok = 0;
01330 }
01331 return(ok);
01332 }
01333
01334 #endif
01335
01336
01337 int chkspecial(ino, ip)
01338 ino_t ino;
01339 d_inode *ip;
01340 {
01341 int i, ok;
01342
01343 ok = 1;
01344 if ((dev_t) ip->i_zone[0] == NO_DEV) {
01345 printf("illegal device number %ld for special file ", ip->i_zone[0]);
01346 printpath(2, 1);
01347 ok = 0;
01348 }
01349
01350
01351
01352
01353 for (i = 1; i < NR_ZONE_NUMS; i++)
01354 if (ip->i_zone[i] != NO_ZONE) {
01355 printf("nonzero zone number %ld for special file ",
01356 ip->i_zone[i]);
01357 printpath(2, 1);
01358 ok = 0;
01359 }
01360 return(ok);
01361 }
01362
01363
01364 int chkmode(ino, ip)
01365 ino_t ino;
01366 d_inode *ip;
01367 {
01368 switch (ip->i_mode & I_TYPE) {
01369 case I_REGULAR:
01370 nregular++;
01371 return chkfile(ino, ip);
01372 case I_DIRECTORY:
01373 ndirectory++;
01374 return chkdirectory(ino, ip);
01375 case I_BLOCK_SPECIAL:
01376 nblkspec++;
01377 return chkspecial(ino, ip);
01378 case I_CHAR_SPECIAL:
01379 ncharspec++;
01380 return chkspecial(ino, ip);
01381 case I_NAMED_PIPE:
01382 npipe++;
01383 return chkfile(ino, ip);
01384 #ifdef I_SYMBOLIC_LINK
01385 case I_SYMBOLIC_LINK:
01386 nsyml++;
01387 return chklink(ino, ip);
01388 #endif
01389 default:
01390 nbadinode++;
01391 printf("bad mode of ");
01392 printpath(1, 0);
01393 printf("mode = %o)", ip->i_mode);
01394 return(0);
01395 }
01396 }
01397
01398
01399 int chkinode(ino, ip)
01400 ino_t ino;
01401 d_inode *ip;
01402 {
01403 if (ino == ROOT_INODE && (ip->i_mode & I_TYPE) != I_DIRECTORY) {
01404 printf("root inode is not a directory ");
01405 printf("(ino = %u, mode = %o)\n", ino, ip->i_mode);
01406 fatal("");
01407 }
01408 if (ip->i_nlinks == 0) {
01409 printf("link count zero of ");
01410 printpath(2, 0);
01411 return(0);
01412 }
01413 nfreeinode--;
01414 setbit(imap, (bit_nr) ino);
01415 if ((unsigned) ip->i_nlinks > SHRT_MAX) {
01416 printf("link count too big in ");
01417 printpath(1, 0);
01418 printf("cnt = %u)\n", (unsigned) ip->i_nlinks);
01419 count[ino] -= SHRT_MAX;
01420 setbit(spec_imap, (bit_nr) ino);
01421 } else {
01422 count[ino] -= (unsigned) ip->i_nlinks;
01423 }
01424 return chkmode(ino, ip);
01425 }
01426
01427
01428 int descendtree(dp)
01429 dir_struct *dp;
01430 {
01431 d_inode inode;
01432 register ino_t ino = dp->d_inum;
01433 register visited;
01434 struct stack stk;
01435
01436 stk.st_dir = dp;
01437 stk.st_next = ftop;
01438 ftop = &stk;
01439 if (bitset(spec_imap, (bit_nr) ino)) {
01440 printf("found inode %u: ", ino);
01441 printpath(0, 1);
01442 }
01443 visited = bitset(imap, (bit_nr) ino);
01444 if (!visited || listing) {
01445 devread(inoaddr(ino), (char *) &inode, INODE_SIZE);
01446 if (listing) list(ino, &inode);
01447 if (!visited && !chkinode(ino, &inode)) {
01448 setbit(spec_imap, (bit_nr) ino);
01449 if (yes("remove")) {
01450 count[ino] += inode.i_nlinks - 1;
01451 clrbit(imap, (bit_nr) ino);
01452 devwrite(inoaddr(ino), nullbuf, INODE_SIZE);
01453 memset((void *) dp, 0, sizeof(dir_struct));
01454 ftop = ftop->st_next;
01455 return(0);
01456 }
01457 }
01458 }
01459 ftop = ftop->st_next;
01460 return(1);
01461 }
01462
01463
01464 void chktree()
01465 {
01466 dir_struct dir;
01467
01468 nfreeinode = sb.s_ninodes;
01469 nfreezone = N_DATA;
01470 dir.d_inum = ROOT_INODE;
01471 dir.d_name[0] = 0;
01472 if (!descendtree(&dir)) fatal("bad root inode");
01473 putchar('\n');
01474 }
01475
01476
01477 void printtotal()
01478 {
01479 printf("blocksize = %5d ", block_size);
01480 printf("zonesize = %5d\n", ZONE_SIZE);
01481 printf("\n");
01482 pr("%8u Regular file%s\n", nregular, "", "s");
01483 pr("%8u Director%s\n", ndirectory, "y", "ies");
01484 pr("%8u Block special file%s\n", nblkspec, "", "s");
01485 pr("%8u Character special file%s\n", ncharspec, "", "s");
01486 if (nbadinode != 0) pr("%6u Bad inode%s\n", nbadinode, "", "s");
01487 pr("%8u Free inode%s\n", nfreeinode, "", "s");
01488 pr("%8u Named pipe%s\n", npipe, "", "s");
01489 pr("%8u Symbolic link%s\n", nsyml, "", "s");
01490
01491
01492
01493
01494
01495
01496 lpr("%8ld Free zone%s\n", nfreezone, "", "s");
01497 }
01498
01499
01500
01501
01502
01503
01504 void chkdev(f, clist, ilist, zlist)
01505 char *f, **clist, **ilist, **zlist;
01506 {
01507 if (automatic) repair = 1;
01508 fsck_device = f;
01509 initvars();
01510
01511 devopen();
01512
01513 getsuper();
01514
01515 if(block_size < _MIN_BLOCK_SIZE || block_size > _MAX_BLOCK_SIZE)
01516 fatal("funny block size");
01517
01518 if(!(rwbuf = malloc(block_size))) fatal("couldn't allocate fs buf (1)");
01519 if(!(nullbuf = malloc(block_size))) fatal("couldn't allocate fs buf (2)");
01520 memset(nullbuf, 0, block_size);
01521
01522 chksuper();
01523
01524 lsi(clist);
01525
01526 getbitmaps();
01527
01528 fillbitmap(spec_imap, (bit_nr) 1, (bit_nr) sb.s_ninodes + 1, ilist);
01529 fillbitmap(spec_zmap, (bit_nr) FIRST, (bit_nr) sb.s_zones, zlist);
01530
01531 getcount();
01532 chktree();
01533 chkmap(zmap, spec_zmap, (bit_nr) FIRST - 1, BLK_ZMAP, N_ZMAP, "zone");
01534 chkcount();
01535 chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP, "inode");
01536 chkilist();
01537 printtotal();
01538
01539 putbitmaps();
01540 freecount();
01541 devclose();
01542
01543 if (changed) printf("----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
01544 }
01545
01546 int main(argc, argv)
01547 int argc;
01548 char **argv;
01549 {
01550 register char **clist = 0, **ilist = 0, **zlist = 0;
01551
01552 register devgiven = 0;
01553 register char *arg;
01554
01555 if ((1 << BITSHIFT) != 8 * sizeof(bitchunk_t)) {
01556 printf("Fsck was compiled with the wrong BITSHIFT!\n");
01557 exit(1);
01558 }
01559
01560 sync();
01561 prog = *argv++;
01562 while ((arg = *argv++) != 0)
01563 if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) {
01564 case 'a': automatic ^= 1; break;
01565 case 'c':
01566 clist = getlist(&argv, "inode");
01567 break;
01568 case 'i':
01569 ilist = getlist(&argv, "inode");
01570 break;
01571 case 'z':
01572 zlist = getlist(&argv, "zone");
01573 break;
01574 case 'r': repair ^= 1; break;
01575 case 'l': listing ^= 1; break;
01576 case 's': listsuper ^= 1; break;
01577 default:
01578 printf("%s: unknown flag '%s'\n", prog, arg);
01579 }
01580 else {
01581 chkdev(arg, clist, ilist, zlist);
01582 clist = 0;
01583 ilist = 0;
01584 zlist = 0;
01585 devgiven = 1;
01586 }
01587 if (!devgiven) {
01588 printf("Usage: fsck [-acilrsz] file\n");
01589 exit(1);
01590 }
01591 return(0);
01592 }