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