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