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