1/* vi: set sw=4 ts=4: */ 2/* 3 * fsck.c - a file system consistency checker for Linux. 4 * 5 * (C) 1991, 1992 Linus Torvalds. This file may be redistributed 6 * as per the GNU copyleft. 7 */ 8 9/* 10 * 09.11.91 - made the first rudimetary functions 11 * 12 * 10.11.91 - updated, does checking, no repairs yet. 13 * Sent out to the mailing-list for testing. 14 * 15 * 14.11.91 - Testing seems to have gone well. Added some 16 * correction-code, and changed some functions. 17 * 18 * 15.11.91 - More correction code. Hopefully it notices most 19 * cases now, and tries to do something about them. 20 * 21 * 16.11.91 - More corrections (thanks to Mika Jalava). Most 22 * things seem to work now. Yeah, sure. 23 * 24 * 25 * 19.04.92 - Had to start over again from this old version, as a 26 * kernel bug ate my enhanced fsck in february. 27 * 28 * 28.02.93 - added support for different directory entry sizes.. 29 * 30 * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with 31 * super-block information 32 * 33 * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform 34 * to that required by fsutil 35 * 36 * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu) 37 * Added support for file system valid flag. Also 38 * added program_version variable and output of 39 * program name and version number when program 40 * is executed. 41 * 42 * 30.10.94 - added support for v2 filesystem 43 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) 44 * 45 * 10.12.94 - added test to prevent checking of mounted fs adapted 46 * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck 47 * program. (Daniel Quinlan, quinlan@yggdrasil.com) 48 * 49 * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such 50 * for modern libcs (janl@math.uio.no, Nicolai Langfeldt) 51 * 52 * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk 53 * (Russell King). He made them for ARM. It would seem 54 * that the ARM is powerful enough to do this in C whereas 55 * i386 and m64k must use assembly to get it fast >:-) 56 * This should make minix fsck systemindependent. 57 * (janl@math.uio.no, Nicolai Langfeldt) 58 * 59 * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler 60 * warnings. Added mc68k bitops from 61 * Joerg Dorchain <dorchain@mpi-sb.mpg.de>. 62 * 63 * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by 64 * Andreas Schwab. 65 * 66 * 1999-02-22 Arkadiusz Mi�kiewicz <misiek@misiek.eu.org> 67 * - added Native Language Support 68 * 69 * 70 * I've had no time to add comments - hopefully the function names 71 * are comments enough. As with all file system checkers, this assumes 72 * the file system is quiescent - don't use it on a mounted device 73 * unless you can be sure nobody is writing to it (and remember that the 74 * kernel can write to it when it searches for files). 75 * 76 * Usuage: fsck [-larvsm] device 77 * -l for a listing of all the filenames 78 * -a for automatic repairs (not implemented) 79 * -r for repairs (interactive) (not implemented) 80 * -v for verbose (tells how many files) 81 * -s for super-block info 82 * -m for minix-like "mode not cleared" warnings 83 * -f force filesystem check even if filesystem marked as valid 84 * 85 * The device may be a block device or a image of one, but this isn't 86 * enforced (but it's not much fun on a character device :-). 87 */ 88 89#include <stdio.h> 90#include <errno.h> 91#include <unistd.h> 92#include <string.h> 93#include <fcntl.h> 94#include <ctype.h> 95#include <stdlib.h> 96#include <termios.h> 97#include <mntent.h> 98#include <sys/param.h> 99#include "busybox.h" 100 101 102 typedef unsigned char u8; 103typedef unsigned short u16; 104typedef unsigned int u32; 105 106 107static const int MINIX_ROOT_INO = 1; 108static const int MINIX_LINK_MAX = 250; 109static const int MINIX2_LINK_MAX = 65530; 110 111static const int MINIX_I_MAP_SLOTS = 8; 112static const int MINIX_Z_MAP_SLOTS = 64; 113static const int MINIX_SUPER_MAGIC = 0x137F; /* original minix fs */ 114static const int MINIX_SUPER_MAGIC2 = 0x138F; /* minix fs, 30 char names */ 115static const int MINIX2_SUPER_MAGIC = 0x2468; /* minix V2 fs */ 116static const int MINIX2_SUPER_MAGIC2 = 0x2478; /* minix V2 fs, 30 char names */ 117static const int MINIX_VALID_FS = 0x0001; /* Clean fs. */ 118static const int MINIX_ERROR_FS = 0x0002; /* fs has errors. */ 119 120#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) 121#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) 122 123static const int MINIX_V1 = 0x0001; /* original minix fs */ 124static const int MINIX_V2 = 0x0002; /* minix V2 fs */ 125 126#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version 127 128/* 129 * This is the original minix inode layout on disk. 130 * Note the 8-bit gid and atime and ctime. 131 */ 132struct minix_inode { 133 u16 i_mode; 134 u16 i_uid; 135 u32 i_size; 136 u32 i_time; 137 u8 i_gid; 138 u8 i_nlinks; 139 u16 i_zone[9]; 140}; 141 142/* 143 * The new minix inode has all the time entries, as well as 144 * long block numbers and a third indirect block (7+1+1+1 145 * instead of 7+1+1). Also, some previously 8-bit values are 146 * now 16-bit. The inode is now 64 bytes instead of 32. 147 */ 148struct minix2_inode { 149 u16 i_mode; 150 u16 i_nlinks; 151 u16 i_uid; 152 u16 i_gid; 153 u32 i_size; 154 u32 i_atime; 155 u32 i_mtime; 156 u32 i_ctime; 157 u32 i_zone[10]; 158}; 159 160/* 161 * minix super-block data on disk 162 */ 163struct minix_super_block { 164 u16 s_ninodes; 165 u16 s_nzones; 166 u16 s_imap_blocks; 167 u16 s_zmap_blocks; 168 u16 s_firstdatazone; 169 u16 s_log_zone_size; 170 u32 s_max_size; 171 u16 s_magic; 172 u16 s_state; 173 u32 s_zones; 174}; 175 176struct minix_dir_entry { 177 u16 inode; 178 char name[0]; 179}; 180 181#define BLOCK_SIZE_BITS 10 182#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS) 183 184#define NAME_MAX 255 /* # chars in a file name */ 185 186#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) 187 188#ifndef BLKGETSIZE 189#define BLKGETSIZE _IO(0x12,96) /* return device size */ 190#endif 191 192#ifndef __linux__ 193#define volatile 194#endif 195 196static const int ROOT_INO = 1; 197 198#define UPPER(size,n) ((size+((n)-1))/(n)) 199#define INODE_SIZE (sizeof(struct minix_inode)) 200#ifdef BB_FEATURE_MINIX2 201#define INODE_SIZE2 (sizeof(struct minix2_inode)) 202#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \ 203 : MINIX_INODES_PER_BLOCK)) 204#else 205#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK)) 206#endif 207#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE) 208 209#define BITS_PER_BLOCK (BLOCK_SIZE<<3) 210 211static char *program_version = "1.2 - 11/11/96"; 212static char *device_name = NULL; 213static int IN; 214static int repair = 0, automatic = 0, verbose = 0, list = 0, show = 215 0, warn_mode = 0, force = 0; 216static int directory = 0, regular = 0, blockdev = 0, chardev = 0, links = 217 0, symlinks = 0, total = 0; 218 219static int changed = 0; /* flags if the filesystem has been changed */ 220static int errors_uncorrected = 0; /* flag if some error was not corrected */ 221static int dirsize = 16; 222static int namelen = 14; 223static int version2 = 0; 224static struct termios termios; 225static int termios_set = 0; 226 227/* File-name data */ 228static const int MAX_DEPTH = 32; 229static int name_depth = 0; 230// static char name_list[MAX_DEPTH][BUFSIZ + 1]; 231static char **name_list = NULL; 232 233static char *inode_buffer = NULL; 234 235#define Inode (((struct minix_inode *) inode_buffer)-1) 236#define Inode2 (((struct minix2_inode *) inode_buffer)-1) 237static char super_block_buffer[BLOCK_SIZE]; 238 239#define Super (*(struct minix_super_block *)super_block_buffer) 240#define INODES ((unsigned long)Super.s_ninodes) 241#ifdef BB_FEATURE_MINIX2 242#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones)) 243#else 244#define ZONES ((unsigned long)(Super.s_nzones)) 245#endif 246#define IMAPS ((unsigned long)Super.s_imap_blocks) 247#define ZMAPS ((unsigned long)Super.s_zmap_blocks) 248#define FIRSTZONE ((unsigned long)Super.s_firstdatazone) 249#define ZONESIZE ((unsigned long)Super.s_log_zone_size) 250#define MAXSIZE ((unsigned long)Super.s_max_size) 251#define MAGIC (Super.s_magic) 252#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS) 253 254static char *inode_map; 255static char *zone_map; 256 257static unsigned char *inode_count = NULL; 258static unsigned char *zone_count = NULL; 259 260static void recursive_check(unsigned int ino); 261#ifdef BB_FEATURE_MINIX2 262static void recursive_check2(unsigned int ino); 263#endif 264 265static inline int bit(char * a,unsigned int i) 266{ 267 return (a[i >> 3] & (1<<(i & 7))) != 0; 268} 269#define inode_in_use(x) (bit(inode_map,(x))) 270#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) 271 272#define mark_inode(x) (setbit(inode_map,(x)),changed=1) 273#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1) 274 275#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1) 276#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1) 277 278static void leave(int) __attribute__ ((noreturn)); 279static void leave(int status) 280{ 281 if (termios_set) 282 tcsetattr(0, TCSANOW, &termios); 283 exit(status); 284} 285 286static void die(const char *str) 287{ 288 error_msg("%s", str); 289 leave(8); 290} 291 292/* 293 * This simply goes through the file-name data and prints out the 294 * current file. 295 */ 296static void print_current_name(void) 297{ 298 int i = 0; 299 300 while (i < name_depth) 301 printf("/%.*s", namelen, name_list[i++]); 302 if (i == 0) 303 printf("/"); 304} 305 306static int ask(const char *string, int def) 307{ 308 int c; 309 310 if (!repair) { 311 printf("\n"); 312 errors_uncorrected = 1; 313 return 0; 314 } 315 if (automatic) { 316 printf("\n"); 317 if (!def) 318 errors_uncorrected = 1; 319 return def; 320 } 321 printf(def ? "%s (y/n)? " : "%s (n/y)? ", string); 322 for (;;) { 323 fflush(stdout); 324 if ((c = getchar()) == EOF) { 325 if (!def) 326 errors_uncorrected = 1; 327 return def; 328 } 329 c = toupper(c); 330 if (c == 'Y') { 331 def = 1; 332 break; 333 } else if (c == 'N') { 334 def = 0; 335 break; 336 } else if (c == ' ' || c == '\n') 337 break; 338 } 339 if (def) 340 printf("y\n"); 341 else { 342 printf("n\n"); 343 errors_uncorrected = 1; 344 } 345 return def; 346} 347 348/* 349 * Make certain that we aren't checking a filesystem that is on a 350 * mounted partition. Code adapted from e2fsck, Copyright (C) 1993, 351 * 1994 Theodore Ts'o. Also licensed under GPL. 352 */ 353static void check_mount(void) 354{ 355 FILE *f; 356 struct mntent *mnt; 357 int cont; 358 int fd; 359 360 if ((f = setmntent(MOUNTED, "r")) == NULL) 361 return; 362 while ((mnt = getmntent(f)) != NULL) 363 if (strcmp(device_name, mnt->mnt_fsname) == 0) 364 break; 365 endmntent(f); 366 if (!mnt) 367 return; 368 369 /* 370 * If the root is mounted read-only, then /etc/mtab is 371 * probably not correct; so we won't issue a warning based on 372 * it. 373 */ 374 fd = open(MOUNTED, O_RDWR); 375 if (fd < 0 && errno == EROFS) 376 return; 377 else 378 close(fd); 379 380 printf("%s is mounted. ", device_name); 381 if (isatty(0) && isatty(1)) 382 cont = ask("Do you really want to continue", 0); 383 else 384 cont = 0; 385 if (!cont) { 386 printf("check aborted.\n"); 387 exit(0); 388 } 389 return; 390} 391 392/* 393 * check_zone_nr checks to see that *nr is a valid zone nr. If it 394 * isn't, it will possibly be repaired. Check_zone_nr sets *corrected 395 * if an error was corrected, and returns the zone (0 for no zone 396 * or a bad zone-number). 397 */ 398static int check_zone_nr(unsigned short *nr, int *corrected) 399{ 400 if (!*nr) 401 return 0; 402 if (*nr < FIRSTZONE) 403 printf("Zone nr < FIRSTZONE in file `"); 404 else if (*nr >= ZONES) 405 printf("Zone nr >= ZONES in file `"); 406 else 407 return *nr; 408 print_current_name(); 409 printf("'."); 410 if (ask("Remove block", 1)) { 411 *nr = 0; 412 *corrected = 1; 413 } 414 return 0; 415} 416 417#ifdef BB_FEATURE_MINIX2 418static int check_zone_nr2(unsigned int *nr, int *corrected) 419{ 420 if (!*nr) 421 return 0; 422 if (*nr < FIRSTZONE) 423 printf("Zone nr < FIRSTZONE in file `"); 424 else if (*nr >= ZONES) 425 printf("Zone nr >= ZONES in file `"); 426 else 427 return *nr; 428 print_current_name(); 429 printf("'."); 430 if (ask("Remove block", 1)) { 431 *nr = 0; 432 *corrected = 1; 433 } 434 return 0; 435} 436#endif 437 438/* 439 * read-block reads block nr into the buffer at addr. 440 */ 441static void read_block(unsigned int nr, char *addr) 442{ 443 if (!nr) { 444 memset(addr, 0, BLOCK_SIZE); 445 return; 446 } 447 if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) { 448 printf("Read error: unable to seek to block in file '"); 449 print_current_name(); 450 printf("'\n"); 451 memset(addr, 0, BLOCK_SIZE); 452 errors_uncorrected = 1; 453 } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) { 454 printf("Read error: bad block in file '"); 455 print_current_name(); 456 printf("'\n"); 457 memset(addr, 0, BLOCK_SIZE); 458 errors_uncorrected = 1; 459 } 460} 461 462/* 463 * write_block writes block nr to disk. 464 */ 465static void write_block(unsigned int nr, char *addr) 466{ 467 if (!nr) 468 return; 469 if (nr < FIRSTZONE || nr >= ZONES) { 470 printf("Internal error: trying to write bad block\n" 471 "Write request ignored\n"); 472 errors_uncorrected = 1; 473 return; 474 } 475 if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) 476 die("seek failed in write_block"); 477 if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) { 478 printf("Write error: bad block in file '"); 479 print_current_name(); 480 printf("'\n"); 481 errors_uncorrected = 1; 482 } 483} 484 485/* 486 * map-block calculates the absolute block nr of a block in a file. 487 * It sets 'changed' if the inode has needed changing, and re-writes 488 * any indirect blocks with errors. 489 */ 490static int map_block(struct minix_inode *inode, unsigned int blknr) 491{ 492 unsigned short ind[BLOCK_SIZE >> 1]; 493 unsigned short dind[BLOCK_SIZE >> 1]; 494 int blk_chg, block, result; 495 496 if (blknr < 7) 497 return check_zone_nr(inode->i_zone + blknr, &changed); 498 blknr -= 7; 499 if (blknr < 512) { 500 block = check_zone_nr(inode->i_zone + 7, &changed); 501 read_block(block, (char *) ind); 502 blk_chg = 0; 503 result = check_zone_nr(blknr + ind, &blk_chg); 504 if (blk_chg) 505 write_block(block, (char *) ind); 506 return result; 507 } 508 blknr -= 512; 509 block = check_zone_nr(inode->i_zone + 8, &changed); 510 read_block(block, (char *) dind); 511 blk_chg = 0; 512 result = check_zone_nr(dind + (blknr / 512), &blk_chg); 513 if (blk_chg) 514 write_block(block, (char *) dind); 515 block = result; 516 read_block(block, (char *) ind); 517 blk_chg = 0; 518 result = check_zone_nr(ind + (blknr % 512), &blk_chg); 519 if (blk_chg) 520 write_block(block, (char *) ind); 521 return result; 522} 523 524#ifdef BB_FEATURE_MINIX2 525static int map_block2(struct minix2_inode *inode, unsigned int blknr) 526{ 527 unsigned int ind[BLOCK_SIZE >> 2]; 528 unsigned int dind[BLOCK_SIZE >> 2]; 529 unsigned int tind[BLOCK_SIZE >> 2]; 530 int blk_chg, block, result; 531 532 if (blknr < 7) 533 return check_zone_nr2(inode->i_zone + blknr, &changed); 534 blknr -= 7; 535 if (blknr < 256) { 536 block = check_zone_nr2(inode->i_zone + 7, &changed); 537 read_block(block, (char *) ind); 538 blk_chg = 0; 539 result = check_zone_nr2(blknr + ind, &blk_chg); 540 if (blk_chg) 541 write_block(block, (char *) ind); 542 return result; 543 } 544 blknr -= 256; 545 if (blknr >= 256 * 256) { 546 block = check_zone_nr2(inode->i_zone + 8, &changed); 547 read_block(block, (char *) dind); 548 blk_chg = 0; 549 result = check_zone_nr2(dind + blknr / 256, &blk_chg); 550 if (blk_chg) 551 write_block(block, (char *) dind); 552 block = result; 553 read_block(block, (char *) ind); 554 blk_chg = 0; 555 result = check_zone_nr2(ind + blknr % 256, &blk_chg); 556 if (blk_chg) 557 write_block(block, (char *) ind); 558 return result; 559 } 560 blknr -= 256 * 256; 561 block = check_zone_nr2(inode->i_zone + 9, &changed); 562 read_block(block, (char *) tind); 563 blk_chg = 0; 564 result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg); 565 if (blk_chg) 566 write_block(block, (char *) tind); 567 block = result; 568 read_block(block, (char *) dind); 569 blk_chg = 0; 570 result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg); 571 if (blk_chg) 572 write_block(block, (char *) dind); 573 block = result; 574 read_block(block, (char *) ind); 575 blk_chg = 0; 576 result = check_zone_nr2(ind + blknr % 256, &blk_chg); 577 if (blk_chg) 578 write_block(block, (char *) ind); 579 return result; 580} 581#endif 582 583static void write_super_block(void) 584{ 585 /* 586 * Set the state of the filesystem based on whether or not there 587 * are uncorrected errors. The filesystem valid flag is 588 * unconditionally set if we get this far. 589 */ 590 Super.s_state |= MINIX_VALID_FS; 591 if (errors_uncorrected) 592 Super.s_state |= MINIX_ERROR_FS; 593 else 594 Super.s_state &= ~MINIX_ERROR_FS; 595 596 if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET)) 597 die("seek failed in write_super_block"); 598 if (BLOCK_SIZE != write(IN, super_block_buffer, BLOCK_SIZE)) 599 die("unable to write super-block"); 600 601 return; 602} 603 604static void write_tables(void) 605{ 606 write_super_block(); 607 608 if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE)) 609 die("Unable to write inode map"); 610 if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE)) 611 die("Unable to write zone map"); 612 if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE)) 613 die("Unable to write inodes"); 614} 615 616static void get_dirsize(void) 617{ 618 int block; 619 char blk[BLOCK_SIZE]; 620 int size; 621 622#ifdef BB_FEATURE_MINIX2 623 if (version2) 624 block = Inode2[ROOT_INO].i_zone[0]; 625 else 626#endif 627 block = Inode[ROOT_INO].i_zone[0]; 628 read_block(block, blk); 629 for (size = 16; size < BLOCK_SIZE; size <<= 1) { 630 if (strcmp(blk + size + 2, "..") == 0) { 631 dirsize = size; 632 namelen = size - 2; 633 return; 634 } 635 } 636 /* use defaults */ 637} 638 639static void read_superblock(void) 640{ 641 if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET)) 642 die("seek failed"); 643 if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE)) 644 die("unable to read super block"); 645 if (MAGIC == MINIX_SUPER_MAGIC) { 646 namelen = 14; 647 dirsize = 16; 648 version2 = 0; 649 } else if (MAGIC == MINIX_SUPER_MAGIC2) { 650 namelen = 30; 651 dirsize = 32; 652 version2 = 0; 653#ifdef BB_FEATURE_MINIX2 654 } else if (MAGIC == MINIX2_SUPER_MAGIC) { 655 namelen = 14; 656 dirsize = 16; 657 version2 = 1; 658 } else if (MAGIC == MINIX2_SUPER_MAGIC2) { 659 namelen = 30; 660 dirsize = 32; 661 version2 = 1; 662#endif 663 } else 664 die("bad magic number in super-block"); 665 if (ZONESIZE != 0 || BLOCK_SIZE != 1024) 666 die("Only 1k blocks/zones supported"); 667 if (IMAPS * BLOCK_SIZE * 8 < INODES + 1) 668 die("bad s_imap_blocks field in super-block"); 669 if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1) 670 die("bad s_zmap_blocks field in super-block"); 671} 672 673static void read_tables(void) 674{ 675 inode_map = xmalloc(IMAPS * BLOCK_SIZE); 676 zone_map = xmalloc(ZMAPS * BLOCK_SIZE); 677 memset(inode_map, 0, sizeof(inode_map)); 678 memset(zone_map, 0, sizeof(zone_map)); 679 inode_buffer = xmalloc(INODE_BUFFER_SIZE); 680 inode_count = xmalloc(INODES + 1); 681 zone_count = xmalloc(ZONES); 682 if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE)) 683 die("Unable to read inode map"); 684 if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE)) 685 die("Unable to read zone map"); 686 if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE)) 687 die("Unable to read inodes"); 688 if (NORM_FIRSTZONE != FIRSTZONE) { 689 printf("Warning: Firstzone != Norm_firstzone\n"); 690 errors_uncorrected = 1; 691 } 692 get_dirsize(); 693 if (show) { 694 printf("%ld inodes\n", INODES); 695 printf("%ld blocks\n", ZONES); 696 printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE); 697 printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE); 698 printf("Maxsize=%ld\n", MAXSIZE); 699 printf("Filesystem state=%d\n", Super.s_state); 700 printf("namelen=%d\n\n", namelen); 701 } 702} 703 704static struct minix_inode *get_inode(unsigned int nr) 705{ 706 struct minix_inode *inode; 707 708 if (!nr || nr > INODES) 709 return NULL; 710 total++; 711 inode = Inode + nr; 712 if (!inode_count[nr]) { 713 if (!inode_in_use(nr)) { 714 printf("Inode %d marked not used, but used for file '", nr); 715 print_current_name(); 716 printf("'\n"); 717 if (repair) { 718 if (ask("Mark in use", 1)) 719 mark_inode(nr); 720 } else { 721 errors_uncorrected = 1; 722 } 723 } 724 if (S_ISDIR(inode->i_mode)) 725 directory++; 726 else if (S_ISREG(inode->i_mode)) 727 regular++; 728 else if (S_ISCHR(inode->i_mode)) 729 chardev++; 730 else if (S_ISBLK(inode->i_mode)) 731 blockdev++; 732 else if (S_ISLNK(inode->i_mode)) 733 symlinks++; 734 else if (S_ISSOCK(inode->i_mode)); 735 else if (S_ISFIFO(inode->i_mode)); 736 else { 737 print_current_name(); 738 printf(" has mode %05o\n", inode->i_mode); 739 } 740 741 } else 742 links++; 743 if (!++inode_count[nr]) { 744 printf("Warning: inode count too big.\n"); 745 inode_count[nr]--; 746 errors_uncorrected = 1; 747 } 748 return inode; 749} 750 751#ifdef BB_FEATURE_MINIX2 752static struct minix2_inode *get_inode2(unsigned int nr) 753{ 754 struct minix2_inode *inode; 755 756 if (!nr || nr > INODES) 757 return NULL; 758 total++; 759 inode = Inode2 + nr; 760 if (!inode_count[nr]) { 761 if (!inode_in_use(nr)) { 762 printf("Inode %d marked not used, but used for file '", nr); 763 print_current_name(); 764 printf("'\n"); 765 if (repair) { 766 if (ask("Mark in use", 1)) 767 mark_inode(nr); 768 else 769 errors_uncorrected = 1; 770 } 771 } 772 if (S_ISDIR(inode->i_mode)) 773 directory++; 774 else if (S_ISREG(inode->i_mode)) 775 regular++; 776 else if (S_ISCHR(inode->i_mode)) 777 chardev++; 778 else if (S_ISBLK(inode->i_mode)) 779 blockdev++; 780 else if (S_ISLNK(inode->i_mode)) 781 symlinks++; 782 else if (S_ISSOCK(inode->i_mode)); 783 else if (S_ISFIFO(inode->i_mode)); 784 else { 785 print_current_name(); 786 printf(" has mode %05o\n", inode->i_mode); 787 } 788 } else 789 links++; 790 if (!++inode_count[nr]) { 791 printf("Warning: inode count too big.\n"); 792 inode_count[nr]--; 793 errors_uncorrected = 1; 794 } 795 return inode; 796} 797#endif 798 799static void check_root(void) 800{ 801 struct minix_inode *inode = Inode + ROOT_INO; 802 803 if (!inode || !S_ISDIR(inode->i_mode)) 804 die("root inode isn't a directory"); 805} 806 807#ifdef BB_FEATURE_MINIX2 808static void check_root2(void) 809{ 810 struct minix2_inode *inode = Inode2 + ROOT_INO; 811 812 if (!inode || !S_ISDIR(inode->i_mode)) 813 die("root inode isn't a directory"); 814} 815#endif 816 817static int add_zone(unsigned short *znr, int *corrected) 818{ 819 int result; 820 int block; 821 822 result = 0; 823 block = check_zone_nr(znr, corrected); 824 if (!block) 825 return 0; 826 if (zone_count[block]) { 827 printf("Block has been used before. Now in file `"); 828 print_current_name(); 829 printf("'."); 830 if (ask("Clear", 1)) { 831 *znr = 0; 832 block = 0; 833 *corrected = 1; 834 } 835 } 836 if (!block) 837 return 0; 838 if (!zone_in_use(block)) { 839 printf("Block %d in file `", block); 840 print_current_name(); 841 printf("' is marked not in use."); 842 if (ask("Correct", 1)) 843 mark_zone(block); 844 } 845 if (!++zone_count[block]) 846 zone_count[block]--; 847 return block; 848} 849 850#ifdef BB_FEATURE_MINIX2 851static int add_zone2(unsigned int *znr, int *corrected) 852{ 853 int result; 854 int block; 855 856 result = 0; 857 block = check_zone_nr2(znr, corrected); 858 if (!block) 859 return 0; 860 if (zone_count[block]) { 861 printf("Block has been used before. Now in file `"); 862 print_current_name(); 863 printf("'."); 864 if (ask("Clear", 1)) { 865 *znr = 0; 866 block = 0; 867 *corrected = 1; 868 } 869 } 870 if (!block) 871 return 0; 872 if (!zone_in_use(block)) { 873 printf("Block %d in file `", block); 874 print_current_name(); 875 printf("' is marked not in use."); 876 if (ask("Correct", 1)) 877 mark_zone(block); 878 } 879 if (!++zone_count[block]) 880 zone_count[block]--; 881 return block; 882} 883#endif 884 885static void add_zone_ind(unsigned short *znr, int *corrected) 886{ 887 static char blk[BLOCK_SIZE]; 888 int i, chg_blk = 0; 889 int block; 890 891 block = add_zone(znr, corrected); 892 if (!block) 893 return; 894 read_block(block, blk); 895 for (i = 0; i < (BLOCK_SIZE >> 1); i++) 896 add_zone(i + (unsigned short *) blk, &chg_blk); 897 if (chg_blk) 898 write_block(block, blk); 899} 900 901#ifdef BB_FEATURE_MINIX2 902static void add_zone_ind2(unsigned int *znr, int *corrected) 903{ 904 static char blk[BLOCK_SIZE]; 905 int i, chg_blk = 0; 906 int block; 907 908 block = add_zone2(znr, corrected); 909 if (!block) 910 return; 911 read_block(block, blk); 912 for (i = 0; i < BLOCK_SIZE >> 2; i++) 913 add_zone2(i + (unsigned int *) blk, &chg_blk); 914 if (chg_blk) 915 write_block(block, blk); 916} 917#endif 918 919static void add_zone_dind(unsigned short *znr, int *corrected) 920{ 921 static char blk[BLOCK_SIZE]; 922 int i, blk_chg = 0; 923 int block; 924 925 block = add_zone(znr, corrected); 926 if (!block) 927 return; 928 read_block(block, blk); 929 for (i = 0; i < (BLOCK_SIZE >> 1); i++) 930 add_zone_ind(i + (unsigned short *) blk, &blk_chg); 931 if (blk_chg) 932 write_block(block, blk); 933} 934 935#ifdef BB_FEATURE_MINIX2 936static void add_zone_dind2(unsigned int *znr, int *corrected) 937{ 938 static char blk[BLOCK_SIZE]; 939 int i, blk_chg = 0; 940 int block; 941 942 block = add_zone2(znr, corrected); 943 if (!block) 944 return; 945 read_block(block, blk); 946 for (i = 0; i < BLOCK_SIZE >> 2; i++) 947 add_zone_ind2(i + (unsigned int *) blk, &blk_chg); 948 if (blk_chg) 949 write_block(block, blk); 950} 951 952static void add_zone_tind2(unsigned int *znr, int *corrected) 953{ 954 static char blk[BLOCK_SIZE]; 955 int i, blk_chg = 0; 956 int block; 957 958 block = add_zone2(znr, corrected); 959 if (!block) 960 return; 961 read_block(block, blk); 962 for (i = 0; i < BLOCK_SIZE >> 2; i++) 963 add_zone_dind2(i + (unsigned int *) blk, &blk_chg); 964 if (blk_chg) 965 write_block(block, blk); 966} 967#endif 968 969static void check_zones(unsigned int i) 970{ 971 struct minix_inode *inode; 972 973 if (!i || i > INODES) 974 return; 975 if (inode_count[i] > 1) /* have we counted this file already? */ 976 return; 977 inode = Inode + i; 978 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && 979 !S_ISLNK(inode->i_mode)) return; 980 for (i = 0; i < 7; i++) 981 add_zone(i + inode->i_zone, &changed); 982 add_zone_ind(7 + inode->i_zone, &changed); 983 add_zone_dind(8 + inode->i_zone, &changed); 984} 985 986#ifdef BB_FEATURE_MINIX2 987static void check_zones2(unsigned int i) 988{ 989 struct minix2_inode *inode; 990 991 if (!i || i > INODES) 992 return; 993 if (inode_count[i] > 1) /* have we counted this file already? */ 994 return; 995 inode = Inode2 + i; 996 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) 997 && !S_ISLNK(inode->i_mode)) 998 return; 999 for (i = 0; i < 7; i++) 1000 add_zone2(i + inode->i_zone, &changed); 1001 add_zone_ind2(7 + inode->i_zone, &changed); 1002 add_zone_dind2(8 + inode->i_zone, &changed); 1003 add_zone_tind2(9 + inode->i_zone, &changed); 1004} 1005#endif 1006 1007static void check_file(struct minix_inode *dir, unsigned int offset) 1008{ 1009 static char blk[BLOCK_SIZE]; 1010 struct minix_inode *inode; 1011 int ino; 1012 char *name; 1013 int block; 1014 1015 block = map_block(dir, offset / BLOCK_SIZE); 1016 read_block(block, blk); 1017 name = blk + (offset % BLOCK_SIZE) + 2; 1018 ino = *(unsigned short *) (name - 2); 1019 if (ino > INODES) { 1020 print_current_name(); 1021 printf(" contains a bad inode number for file '"); 1022 printf("%.*s'.", namelen, name); 1023 if (ask(" Remove", 1)) { 1024 *(unsigned short *) (name - 2) = 0; 1025 write_block(block, blk); 1026 } 1027 ino = 0; 1028 } 1029 if (name_depth < MAX_DEPTH) 1030 strncpy(name_list[name_depth], name, namelen); 1031 name_depth++; 1032 inode = get_inode(ino); 1033 name_depth--; 1034 if (!offset) { 1035 if (!inode || strcmp(".", name)) { 1036 print_current_name(); 1037 printf(": bad directory: '.' isn't first\n"); 1038 errors_uncorrected = 1; 1039 } else 1040 return; 1041 } 1042 if (offset == dirsize) { 1043 if (!inode || strcmp("..", name)) { 1044 print_current_name(); 1045 printf(": bad directory: '..' isn't second\n"); 1046 errors_uncorrected = 1; 1047 } else 1048 return; 1049 } 1050 if (!inode) 1051 return; 1052 if (name_depth < MAX_DEPTH) 1053 strncpy(name_list[name_depth], name, namelen); 1054 name_depth++; 1055 if (list) { 1056 if (verbose) 1057 printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks); 1058 print_current_name(); 1059 if (S_ISDIR(inode->i_mode)) 1060 printf(":\n"); 1061 else 1062 printf("\n"); 1063 } 1064 check_zones(ino); 1065 if (inode && S_ISDIR(inode->i_mode)) 1066 recursive_check(ino); 1067 name_depth--; 1068 return; 1069} 1070 1071#ifdef BB_FEATURE_MINIX2 1072static void check_file2(struct minix2_inode *dir, unsigned int offset) 1073{ 1074 static char blk[BLOCK_SIZE]; 1075 struct minix2_inode *inode; 1076 int ino; 1077 char *name; 1078 int block; 1079 1080 block = map_block2(dir, offset / BLOCK_SIZE); 1081 read_block(block, blk); 1082 name = blk + (offset % BLOCK_SIZE) + 2; 1083 ino = *(unsigned short *) (name - 2); 1084 if (ino > INODES) { 1085 print_current_name(); 1086 printf(" contains a bad inode number for file '"); 1087 printf("%.*s'.", namelen, name); 1088 if (ask(" Remove", 1)) { 1089 *(unsigned short *) (name - 2) = 0; 1090 write_block(block, blk); 1091 } 1092 ino = 0; 1093 } 1094 if (name_depth < MAX_DEPTH) 1095 strncpy(name_list[name_depth], name, namelen); 1096 name_depth++; 1097 inode = get_inode2(ino); 1098 name_depth--; 1099 if (!offset) { 1100 if (!inode || strcmp(".", name)) { 1101 print_current_name(); 1102 printf(": bad directory: '.' isn't first\n"); 1103 errors_uncorrected = 1; 1104 } else 1105 return; 1106 } 1107 if (offset == dirsize) { 1108 if (!inode || strcmp("..", name)) { 1109 print_current_name(); 1110 printf(": bad directory: '..' isn't second\n"); 1111 errors_uncorrected = 1; 1112 } else 1113 return; 1114 } 1115 if (!inode) 1116 return; 1117 name_depth++; 1118 if (list) { 1119 if (verbose) 1120 printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks); 1121 print_current_name(); 1122 if (S_ISDIR(inode->i_mode)) 1123 printf(":\n"); 1124 else 1125 printf("\n"); 1126 } 1127 check_zones2(ino); 1128 if (inode && S_ISDIR(inode->i_mode)) 1129 recursive_check2(ino); 1130 name_depth--; 1131 return; 1132} 1133#endif 1134 1135static void recursive_check(unsigned int ino) 1136{ 1137 struct minix_inode *dir; 1138 unsigned int offset; 1139 1140 dir = Inode + ino; 1141 if (!S_ISDIR(dir->i_mode)) 1142 die("internal error"); 1143 if (dir->i_size < 2 * dirsize) { 1144 print_current_name(); 1145 printf(": bad directory: size<32"); 1146 errors_uncorrected = 1; 1147 } 1148 for (offset = 0; offset < dir->i_size; offset += dirsize) 1149 check_file(dir, offset); 1150} 1151 1152#ifdef BB_FEATURE_MINIX2 1153static void recursive_check2(unsigned int ino) 1154{ 1155 struct minix2_inode *dir; 1156 unsigned int offset; 1157 1158 dir = Inode2 + ino; 1159 if (!S_ISDIR(dir->i_mode)) 1160 die("internal error"); 1161 if (dir->i_size < 2 * dirsize) { 1162 print_current_name(); 1163 printf(": bad directory: size < 32"); 1164 errors_uncorrected = 1; 1165 } 1166 for (offset = 0; offset < dir->i_size; offset += dirsize) 1167 check_file2(dir, offset); 1168} 1169#endif 1170 1171static int bad_zone(int i) 1172{ 1173 char buffer[1024]; 1174 1175 if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET)) 1176 die("seek failed in bad_zone"); 1177 return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE)); 1178} 1179 1180static void check_counts(void) 1181{ 1182 int i; 1183 1184 for (i = 1; i <= INODES; i++) { 1185 if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) { 1186 printf("Inode %d mode not cleared.", i); 1187 if (ask("Clear", 1)) { 1188 Inode[i].i_mode = 0; 1189 changed = 1; 1190 } 1191 } 1192 if (!inode_count[i]) { 1193 if (!inode_in_use(i)) 1194 continue; 1195 printf("Inode %d not used, marked used in the bitmap.", i); 1196 if (ask("Clear", 1)) 1197 unmark_inode(i); 1198 continue; 1199 } 1200 if (!inode_in_use(i)) { 1201 printf("Inode %d used, marked unused in the bitmap.", i); 1202 if (ask("Set", 1)) 1203 mark_inode(i); 1204 } 1205 if (Inode[i].i_nlinks != inode_count[i]) { 1206 printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.", 1207 i, Inode[i].i_mode, Inode[i].i_nlinks, inode_count[i]); 1208 if (ask("Set i_nlinks to count", 1)) { 1209 Inode[i].i_nlinks = inode_count[i]; 1210 changed = 1; 1211 } 1212 } 1213 } 1214 for (i = FIRSTZONE; i < ZONES; i++) { 1215 if (zone_in_use(i) == zone_count[i]) 1216 continue; 1217 if (!zone_count[i]) { 1218 if (bad_zone(i)) 1219 continue; 1220 printf("Zone %d: marked in use, no file uses it.", i); 1221 if (ask("Unmark", 1)) 1222 unmark_zone(i); 1223 continue; 1224 } 1225 printf("Zone %d: %sin use, counted=%d\n", 1226 i, zone_in_use(i) ? "" : "not ", zone_count[i]); 1227 } 1228} 1229 1230#ifdef BB_FEATURE_MINIX2 1231static void check_counts2(void) 1232{ 1233 int i; 1234 1235 for (i = 1; i <= INODES; i++) { 1236 if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) { 1237 printf("Inode %d mode not cleared.", i); 1238 if (ask("Clear", 1)) { 1239 Inode2[i].i_mode = 0; 1240 changed = 1; 1241 } 1242 } 1243 if (!inode_count[i]) { 1244 if (!inode_in_use(i)) 1245 continue; 1246 printf("Inode %d not used, marked used in the bitmap.", i); 1247 if (ask("Clear", 1)) 1248 unmark_inode(i); 1249 continue; 1250 } 1251 if (!inode_in_use(i)) { 1252 printf("Inode %d used, marked unused in the bitmap.", i); 1253 if (ask("Set", 1)) 1254 mark_inode(i); 1255 } 1256 if (Inode2[i].i_nlinks != inode_count[i]) { 1257 printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.", 1258 i, Inode2[i].i_mode, Inode2[i].i_nlinks, 1259 inode_count[i]); 1260 if (ask("Set i_nlinks to count", 1)) { 1261 Inode2[i].i_nlinks = inode_count[i]; 1262 changed = 1; 1263 } 1264 } 1265 } 1266 for (i = FIRSTZONE; i < ZONES; i++) { 1267 if (zone_in_use(i) == zone_count[i]) 1268 continue; 1269 if (!zone_count[i]) { 1270 if (bad_zone(i)) 1271 continue; 1272 printf("Zone %d: marked in use, no file uses it.", i); 1273 if (ask("Unmark", 1)) 1274 unmark_zone(i); 1275 continue; 1276 } 1277 printf("Zone %d: %sin use, counted=%d\n", 1278 i, zone_in_use(i) ? "" : "not ", zone_count[i]); 1279 } 1280} 1281#endif 1282 1283static void check(void) 1284{ 1285 memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count)); 1286 memset(zone_count, 0, ZONES * sizeof(*zone_count)); 1287 check_zones(ROOT_INO); 1288 recursive_check(ROOT_INO); 1289 check_counts(); 1290} 1291 1292#ifdef BB_FEATURE_MINIX2 1293static void check2(void) 1294{ 1295 memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count)); 1296 memset(zone_count, 0, ZONES * sizeof(*zone_count)); 1297 check_zones2(ROOT_INO); 1298 recursive_check2(ROOT_INO); 1299 check_counts2(); 1300} 1301#endif 1302 1303/* Wed Feb 9 15:17:06 MST 2000 */ 1304/* dynamically allocate name_list (instead of making it static) */ 1305static void alloc_name_list(void) 1306{ 1307 int i; 1308 1309 name_list = xmalloc(sizeof(char *) * MAX_DEPTH); 1310 for (i = 0; i < MAX_DEPTH; i++) 1311 name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1); 1312} 1313 1314#ifdef BB_FEATURE_CLEAN_UP 1315/* execute this atexit() to deallocate name_list[] */ 1316/* piptigger was here */ 1317static void free_name_list(void) 1318{ 1319 int i; 1320 1321 if (name_list) { 1322 for (i = 0; i < MAX_DEPTH; i++) { 1323 if (name_list[i]) { 1324 free(name_list[i]); 1325 } 1326 } 1327 free(name_list); 1328 } 1329} 1330#endif 1331 1332extern int fsck_minix_main(int argc, char **argv) 1333{ 1334 struct termios tmp; 1335 int count; 1336 int retcode = 0; 1337 1338 alloc_name_list(); 1339#ifdef BB_FEATURE_CLEAN_UP 1340 /* Don't bother to free memory. Exit does 1341 * that automagically, so we can save a few bytes */ 1342 atexit(free_name_list); 1343#endif 1344 1345 if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) 1346 die("bad inode size"); 1347#ifdef BB_FEATURE_MINIX2 1348 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) 1349 die("bad v2 inode size"); 1350#endif 1351 while (argc-- > 1) { 1352 argv++; 1353 if (argv[0][0] != '-') { 1354 if (device_name) 1355 show_usage(); 1356 else 1357 device_name = argv[0]; 1358 } else 1359 while (*++argv[0]) 1360 switch (argv[0][0]) { 1361 case 'l': 1362 list = 1; 1363 break; 1364 case 'a': 1365 automatic = 1; 1366 repair = 1; 1367 break; 1368 case 'r': 1369 automatic = 0; 1370 repair = 1; 1371 break; 1372 case 'v': 1373 verbose = 1; 1374 break; 1375 case 's': 1376 show = 1; 1377 break; 1378 case 'm': 1379 warn_mode = 1; 1380 break; 1381 case 'f': 1382 force = 1; 1383 break; 1384 default: 1385 show_usage(); 1386 } 1387 } 1388 if (!device_name) 1389 show_usage(); 1390 check_mount(); /* trying to check a mounted filesystem? */ 1391 if (repair && !automatic) { 1392 if (!isatty(0) || !isatty(1)) 1393 die("need terminal for interactive repairs"); 1394 } 1395 IN = open(device_name, repair ? O_RDWR : O_RDONLY); 1396 if (IN < 0){ 1397 fprintf(stderr,"unable to open device '%s'.\n",device_name); 1398 leave(8); 1399 } 1400 for (count = 0; count < 3; count++) 1401 sync(); 1402 read_superblock(); 1403 1404 /* 1405 * Determine whether or not we should continue with the checking. 1406 * This is based on the status of the filesystem valid and error 1407 * flags and whether or not the -f switch was specified on the 1408 * command line. 1409 */ 1410 printf("%s, %s\n", applet_name, program_version); 1411 if (!(Super.s_state & MINIX_ERROR_FS) && 1412 (Super.s_state & MINIX_VALID_FS) && !force) { 1413 if (repair) 1414 printf("%s is clean, no check.\n", device_name); 1415 return retcode; 1416 } else if (force) 1417 printf("Forcing filesystem check on %s.\n", device_name); 1418 else if (repair) 1419 printf("Filesystem on %s is dirty, needs checking.\n", 1420 device_name); 1421 1422 read_tables(); 1423 1424 if (repair && !automatic) { 1425 tcgetattr(0, &termios); 1426 tmp = termios; 1427 tmp.c_lflag &= ~(ICANON | ECHO); 1428 tcsetattr(0, TCSANOW, &tmp); 1429 termios_set = 1; 1430 } 1431#ifdef BB_FEATURE_MINIX2 1432 if (version2) { 1433 check_root2(); 1434 check2(); 1435 } else 1436#endif 1437 { 1438 check_root(); 1439 check(); 1440 } 1441 if (verbose) { 1442 int i, free_cnt; 1443 1444 for (i = 1, free_cnt = 0; i <= INODES; i++) 1445 if (!inode_in_use(i)) 1446 free_cnt++; 1447 printf("\n%6ld inodes used (%ld%%)\n", (INODES - free_cnt), 1448 100 * (INODES - free_cnt) / INODES); 1449 for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++) 1450 if (!zone_in_use(i)) 1451 free_cnt++; 1452 printf("%6ld zones used (%ld%%)\n", (ZONES - free_cnt), 1453 100 * (ZONES - free_cnt) / ZONES); 1454 printf("\n%6d regular files\n" 1455 "%6d directories\n" 1456 "%6d character device files\n" 1457 "%6d block device files\n" 1458 "%6d links\n" 1459 "%6d symbolic links\n" 1460 "------\n" 1461 "%6d files\n", 1462 regular, directory, chardev, blockdev, 1463 links - 2 * directory + 1, symlinks, 1464 total - 2 * directory + 1); 1465 } 1466 if (changed) { 1467 write_tables(); 1468 printf("----------------------------\n" 1469 "FILE SYSTEM HAS BEEN CHANGED\n" 1470 "----------------------------\n"); 1471 for (count = 0; count < 3; count++) 1472 sync(); 1473 } else if (repair) 1474 write_super_block(); 1475 1476 if (repair && !automatic) 1477 tcsetattr(0, TCSANOW, &termios); 1478 1479 if (changed) 1480 retcode += 3; 1481 if (errors_uncorrected) 1482 retcode += 4; 1483 return retcode; 1484} 1485