fsck_minix.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299
  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.
  6. *
  7. * Licensed under GPLv2, see file LICENSE in this tarball for details.
  8. */
  9. /*
  10. * 09.11.91 - made the first rudimentary 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. * superblock 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 system-independent.
  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 Mickiewicz <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. * Usage: 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 superblock 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. #include <mntent.h>
  89. #include "libbb.h"
  90. #include "minix.h"
  91. #ifndef BLKGETSIZE
  92. #define BLKGETSIZE _IO(0x12,96) /* return device size */
  93. #endif
  94. struct BUG_bad_inode_size {
  95. char BUG_bad_inode1_size[(INODE_SIZE1 * MINIX1_INODES_PER_BLOCK != BLOCK_SIZE) ? -1 : 1];
  96. #if ENABLE_FEATURE_MINIX2
  97. char BUG_bad_inode2_size[(INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) ? -1 : 1];
  98. #endif
  99. };
  100. enum {
  101. #ifdef UNUSED
  102. MINIX1_LINK_MAX = 250,
  103. MINIX2_LINK_MAX = 65530,
  104. MINIX_I_MAP_SLOTS = 8,
  105. MINIX_Z_MAP_SLOTS = 64,
  106. MINIX_V1 = 0x0001, /* original minix fs */
  107. MINIX_V2 = 0x0002, /* minix V2 fs */
  108. #endif
  109. MINIX_NAME_MAX = 255, /* # chars in a file name */
  110. };
  111. #if !ENABLE_FEATURE_MINIX2
  112. enum { version2 = 0 };
  113. #endif
  114. enum { MAX_DEPTH = 32 };
  115. enum { dev_fd = 3 };
  116. struct globals {
  117. #if ENABLE_FEATURE_MINIX2
  118. smallint version2;
  119. #endif
  120. smallint changed; /* is filesystem modified? */
  121. smallint errors_uncorrected; /* flag if some error was not corrected */
  122. smallint termios_set;
  123. smallint dirsize;
  124. smallint namelen;
  125. const char *device_name;
  126. int directory, regular, blockdev, chardev, links, symlinks, total;
  127. char *inode_buffer;
  128. char *inode_map;
  129. char *zone_map;
  130. unsigned char *inode_count;
  131. unsigned char *zone_count;
  132. /* File-name data */
  133. int name_depth;
  134. char *name_component[MAX_DEPTH+1];
  135. /* Bigger stuff */
  136. struct termios sv_termios;
  137. char superblock_buffer[BLOCK_SIZE];
  138. char add_zone_ind_blk[BLOCK_SIZE];
  139. char add_zone_dind_blk[BLOCK_SIZE];
  140. IF_FEATURE_MINIX2(char add_zone_tind_blk[BLOCK_SIZE];)
  141. char check_file_blk[BLOCK_SIZE];
  142. /* File-name data */
  143. char current_name[MAX_DEPTH * MINIX_NAME_MAX];
  144. };
  145. #define G (*ptr_to_globals)
  146. #if ENABLE_FEATURE_MINIX2
  147. #define version2 (G.version2 )
  148. #endif
  149. #define changed (G.changed )
  150. #define errors_uncorrected (G.errors_uncorrected )
  151. #define termios_set (G.termios_set )
  152. #define dirsize (G.dirsize )
  153. #define namelen (G.namelen )
  154. #define device_name (G.device_name )
  155. #define directory (G.directory )
  156. #define regular (G.regular )
  157. #define blockdev (G.blockdev )
  158. #define chardev (G.chardev )
  159. #define links (G.links )
  160. #define symlinks (G.symlinks )
  161. #define total (G.total )
  162. #define inode_buffer (G.inode_buffer )
  163. #define inode_map (G.inode_map )
  164. #define zone_map (G.zone_map )
  165. #define inode_count (G.inode_count )
  166. #define zone_count (G.zone_count )
  167. #define name_depth (G.name_depth )
  168. #define name_component (G.name_component )
  169. #define sv_termios (G.sv_termios )
  170. #define superblock_buffer (G.superblock_buffer )
  171. #define add_zone_ind_blk (G.add_zone_ind_blk )
  172. #define add_zone_dind_blk (G.add_zone_dind_blk )
  173. #define add_zone_tind_blk (G.add_zone_tind_blk )
  174. #define check_file_blk (G.check_file_blk )
  175. #define current_name (G.current_name )
  176. #define INIT_G() do { \
  177. SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
  178. dirsize = 16; \
  179. namelen = 14; \
  180. current_name[0] = '/'; \
  181. /*current_name[1] = '\0';*/ \
  182. name_component[0] = &current_name[0]; \
  183. } while (0)
  184. #define OPTION_STR "larvsmf"
  185. enum {
  186. OPT_l = (1 << 0),
  187. OPT_a = (1 << 1),
  188. OPT_r = (1 << 2),
  189. OPT_v = (1 << 3),
  190. OPT_s = (1 << 4),
  191. OPT_w = (1 << 5),
  192. OPT_f = (1 << 6),
  193. };
  194. #define OPT_list (option_mask32 & OPT_l)
  195. #define OPT_automatic (option_mask32 & OPT_a)
  196. #define OPT_repair (option_mask32 & OPT_r)
  197. #define OPT_verbose (option_mask32 & OPT_v)
  198. #define OPT_show (option_mask32 & OPT_s)
  199. #define OPT_warn_mode (option_mask32 & OPT_w)
  200. #define OPT_force (option_mask32 & OPT_f)
  201. /* non-automatic repairs requested? */
  202. #define OPT_manual ((option_mask32 & (OPT_a|OPT_r)) == OPT_r)
  203. #define Inode1 (((struct minix1_inode *) inode_buffer)-1)
  204. #define Inode2 (((struct minix2_inode *) inode_buffer)-1)
  205. #define Super (*(struct minix_superblock *)(superblock_buffer))
  206. #if ENABLE_FEATURE_MINIX2
  207. # define ZONES ((unsigned)(version2 ? Super.s_zones : Super.s_nzones))
  208. #else
  209. # define ZONES ((unsigned)(Super.s_nzones))
  210. #endif
  211. #define INODES ((unsigned)Super.s_ninodes)
  212. #define IMAPS ((unsigned)Super.s_imap_blocks)
  213. #define ZMAPS ((unsigned)Super.s_zmap_blocks)
  214. #define FIRSTZONE ((unsigned)Super.s_firstdatazone)
  215. #define ZONESIZE ((unsigned)Super.s_log_zone_size)
  216. #define MAXSIZE ((unsigned)Super.s_max_size)
  217. #define MAGIC (Super.s_magic)
  218. /* gcc likes this more (code is smaller) than macro variant */
  219. static ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n)
  220. {
  221. return (size + n-1) / n;
  222. }
  223. #if !ENABLE_FEATURE_MINIX2
  224. #define INODE_BLOCKS div_roundup(INODES, MINIX1_INODES_PER_BLOCK)
  225. #else
  226. #define INODE_BLOCKS div_roundup(INODES, \
  227. (version2 ? MINIX2_INODES_PER_BLOCK : MINIX1_INODES_PER_BLOCK))
  228. #endif
  229. #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
  230. #define NORM_FIRSTZONE (2 + IMAPS + ZMAPS + INODE_BLOCKS)
  231. /* Before you ask "where they come from?": */
  232. /* setbit/clrbit are supplied by sys/param.h */
  233. static int minix_bit(const char *a, unsigned i)
  234. {
  235. return (a[i >> 3] & (1<<(i & 7)));
  236. }
  237. static void minix_setbit(char *a, unsigned i)
  238. {
  239. setbit(a, i);
  240. changed = 1;
  241. }
  242. static void minix_clrbit(char *a, unsigned i)
  243. {
  244. clrbit(a, i);
  245. changed = 1;
  246. }
  247. /* Note: do not assume 0/1, it is 0/nonzero */
  248. #define zone_in_use(x) (minix_bit(zone_map,(x)-FIRSTZONE+1))
  249. #define inode_in_use(x) (minix_bit(inode_map,(x)))
  250. #define mark_inode(x) (minix_setbit(inode_map,(x)))
  251. #define unmark_inode(x) (minix_clrbit(inode_map,(x)))
  252. #define mark_zone(x) (minix_setbit(zone_map,(x)-FIRSTZONE+1))
  253. #define unmark_zone(x) (minix_clrbit(zone_map,(x)-FIRSTZONE+1))
  254. static void recursive_check(unsigned ino);
  255. #if ENABLE_FEATURE_MINIX2
  256. static void recursive_check2(unsigned ino);
  257. #endif
  258. static void die(const char *str) NORETURN;
  259. static void die(const char *str)
  260. {
  261. if (termios_set)
  262. tcsetattr_stdin_TCSANOW(&sv_termios);
  263. bb_error_msg_and_die("%s", str);
  264. }
  265. static void push_filename(const char *name)
  266. {
  267. // /dir/dir/dir/file
  268. // ^ ^ ^
  269. // [0] [1] [2] <-name_component[i]
  270. if (name_depth < MAX_DEPTH) {
  271. int len;
  272. char *p = name_component[name_depth];
  273. *p++ = '/';
  274. len = sprintf(p, "%.*s", namelen, name);
  275. name_component[name_depth + 1] = p + len;
  276. }
  277. name_depth++;
  278. }
  279. static void pop_filename(void)
  280. {
  281. name_depth--;
  282. if (name_depth < MAX_DEPTH) {
  283. *name_component[name_depth] = '\0';
  284. if (!name_depth) {
  285. current_name[0] = '/';
  286. current_name[1] = '\0';
  287. }
  288. }
  289. }
  290. static int ask(const char *string, int def)
  291. {
  292. int c;
  293. if (!OPT_repair) {
  294. bb_putchar('\n');
  295. errors_uncorrected = 1;
  296. return 0;
  297. }
  298. if (OPT_automatic) {
  299. bb_putchar('\n');
  300. if (!def)
  301. errors_uncorrected = 1;
  302. return def;
  303. }
  304. printf(def ? "%s (y/n)? " : "%s (n/y)? ", string);
  305. for (;;) {
  306. fflush(stdout);
  307. c = getchar();
  308. if (c == EOF) {
  309. if (!def)
  310. errors_uncorrected = 1;
  311. return def;
  312. }
  313. c = toupper(c);
  314. if (c == 'Y') {
  315. def = 1;
  316. break;
  317. } else if (c == 'N') {
  318. def = 0;
  319. break;
  320. } else if (c == ' ' || c == '\n')
  321. break;
  322. }
  323. if (def)
  324. printf("y\n");
  325. else {
  326. printf("n\n");
  327. errors_uncorrected = 1;
  328. }
  329. return def;
  330. }
  331. /*
  332. * Make certain that we aren't checking a filesystem that is on a
  333. * mounted partition. Code adapted from e2fsck, Copyright (C) 1993,
  334. * 1994 Theodore Ts'o. Also licensed under GPL.
  335. */
  336. static void check_mount(void)
  337. {
  338. if (find_mount_point(device_name, 0)) {
  339. int cont;
  340. #if ENABLE_FEATURE_MTAB_SUPPORT
  341. /*
  342. * If the root is mounted read-only, then /etc/mtab is
  343. * probably not correct; so we won't issue a warning based on
  344. * it.
  345. */
  346. int fd = open(bb_path_mtab_file, O_RDWR);
  347. if (fd < 0 && errno == EROFS)
  348. return;
  349. close(fd);
  350. #endif
  351. printf("%s is mounted. ", device_name);
  352. cont = 0;
  353. if (isatty(0) && isatty(1))
  354. cont = ask("Do you really want to continue", 0);
  355. if (!cont) {
  356. printf("Check aborted\n");
  357. exit(EXIT_SUCCESS);
  358. }
  359. }
  360. }
  361. /*
  362. * check_zone_nr checks to see that *nr is a valid zone nr. If it
  363. * isn't, it will possibly be repaired. Check_zone_nr sets *corrected
  364. * if an error was corrected, and returns the zone (0 for no zone
  365. * or a bad zone-number).
  366. */
  367. static int check_zone_nr2(uint32_t *nr, smallint *corrected)
  368. {
  369. const char *msg;
  370. if (!*nr)
  371. return 0;
  372. if (*nr < FIRSTZONE)
  373. msg = "< FIRSTZONE";
  374. else if (*nr >= ZONES)
  375. msg = ">= ZONES";
  376. else
  377. return *nr;
  378. printf("Zone nr %s in file '%s'. ", msg, current_name);
  379. if (ask("Remove block", 1)) {
  380. *nr = 0;
  381. *corrected = 1;
  382. }
  383. return 0;
  384. }
  385. static int check_zone_nr(uint16_t *nr, smallint *corrected)
  386. {
  387. uint32_t nr32 = *nr;
  388. int r = check_zone_nr2(&nr32, corrected);
  389. *nr = (uint16_t)nr32;
  390. return r;
  391. }
  392. /*
  393. * read-block reads block nr into the buffer at addr.
  394. */
  395. static void read_block(unsigned nr, void *addr)
  396. {
  397. if (!nr) {
  398. memset(addr, 0, BLOCK_SIZE);
  399. return;
  400. }
  401. xlseek(dev_fd, BLOCK_SIZE * nr, SEEK_SET);
  402. if (BLOCK_SIZE != full_read(dev_fd, addr, BLOCK_SIZE)) {
  403. printf("%s: bad block %u in file '%s'\n",
  404. bb_msg_read_error, nr, current_name);
  405. errors_uncorrected = 1;
  406. memset(addr, 0, BLOCK_SIZE);
  407. }
  408. }
  409. /*
  410. * write_block writes block nr to disk.
  411. */
  412. static void write_block(unsigned nr, void *addr)
  413. {
  414. if (!nr)
  415. return;
  416. if (nr < FIRSTZONE || nr >= ZONES) {
  417. printf("Internal error: trying to write bad block\n"
  418. "Write request ignored\n");
  419. errors_uncorrected = 1;
  420. return;
  421. }
  422. xlseek(dev_fd, BLOCK_SIZE * nr, SEEK_SET);
  423. if (BLOCK_SIZE != full_write(dev_fd, addr, BLOCK_SIZE)) {
  424. printf("%s: bad block %u in file '%s'\n",
  425. bb_msg_write_error, nr, current_name);
  426. errors_uncorrected = 1;
  427. }
  428. }
  429. /*
  430. * map_block calculates the absolute block nr of a block in a file.
  431. * It sets 'changed' if the inode has needed changing, and re-writes
  432. * any indirect blocks with errors.
  433. */
  434. static int map_block(struct minix1_inode *inode, unsigned blknr)
  435. {
  436. uint16_t ind[BLOCK_SIZE >> 1];
  437. int block, result;
  438. smallint blk_chg;
  439. if (blknr < 7)
  440. return check_zone_nr(inode->i_zone + blknr, &changed);
  441. blknr -= 7;
  442. if (blknr < 512) {
  443. block = check_zone_nr(inode->i_zone + 7, &changed);
  444. goto common;
  445. }
  446. blknr -= 512;
  447. block = check_zone_nr(inode->i_zone + 8, &changed);
  448. read_block(block, ind); /* double indirect */
  449. blk_chg = 0;
  450. result = check_zone_nr(&ind[blknr / 512], &blk_chg);
  451. if (blk_chg)
  452. write_block(block, ind);
  453. block = result;
  454. common:
  455. read_block(block, ind);
  456. blk_chg = 0;
  457. result = check_zone_nr(&ind[blknr % 512], &blk_chg);
  458. if (blk_chg)
  459. write_block(block, ind);
  460. return result;
  461. }
  462. #if ENABLE_FEATURE_MINIX2
  463. static int map_block2(struct minix2_inode *inode, unsigned blknr)
  464. {
  465. uint32_t ind[BLOCK_SIZE >> 2];
  466. int block, result;
  467. smallint blk_chg;
  468. if (blknr < 7)
  469. return check_zone_nr2(inode->i_zone + blknr, &changed);
  470. blknr -= 7;
  471. if (blknr < 256) {
  472. block = check_zone_nr2(inode->i_zone + 7, &changed);
  473. goto common2;
  474. }
  475. blknr -= 256;
  476. if (blknr < 256 * 256) {
  477. block = check_zone_nr2(inode->i_zone + 8, &changed);
  478. goto common1;
  479. }
  480. blknr -= 256 * 256;
  481. block = check_zone_nr2(inode->i_zone + 9, &changed);
  482. read_block(block, ind); /* triple indirect */
  483. blk_chg = 0;
  484. result = check_zone_nr2(&ind[blknr / (256 * 256)], &blk_chg);
  485. if (blk_chg)
  486. write_block(block, ind);
  487. block = result;
  488. common1:
  489. read_block(block, ind); /* double indirect */
  490. blk_chg = 0;
  491. result = check_zone_nr2(&ind[(blknr / 256) % 256], &blk_chg);
  492. if (blk_chg)
  493. write_block(block, ind);
  494. block = result;
  495. common2:
  496. read_block(block, ind);
  497. blk_chg = 0;
  498. result = check_zone_nr2(&ind[blknr % 256], &blk_chg);
  499. if (blk_chg)
  500. write_block(block, ind);
  501. return result;
  502. }
  503. #endif
  504. static void write_superblock(void)
  505. {
  506. /*
  507. * Set the state of the filesystem based on whether or not there
  508. * are uncorrected errors. The filesystem valid flag is
  509. * unconditionally set if we get this far.
  510. */
  511. Super.s_state |= MINIX_VALID_FS | MINIX_ERROR_FS;
  512. if (!errors_uncorrected)
  513. Super.s_state &= ~MINIX_ERROR_FS;
  514. xlseek(dev_fd, BLOCK_SIZE, SEEK_SET);
  515. if (BLOCK_SIZE != full_write(dev_fd, superblock_buffer, BLOCK_SIZE))
  516. die("cannot write superblock");
  517. }
  518. static void write_tables(void)
  519. {
  520. write_superblock();
  521. if (IMAPS * BLOCK_SIZE != write(dev_fd, inode_map, IMAPS * BLOCK_SIZE))
  522. die("cannot write inode map");
  523. if (ZMAPS * BLOCK_SIZE != write(dev_fd, zone_map, ZMAPS * BLOCK_SIZE))
  524. die("cannot write zone map");
  525. if (INODE_BUFFER_SIZE != write(dev_fd, inode_buffer, INODE_BUFFER_SIZE))
  526. die("cannot write inodes");
  527. }
  528. static void get_dirsize(void)
  529. {
  530. int block;
  531. char blk[BLOCK_SIZE];
  532. int size;
  533. #if ENABLE_FEATURE_MINIX2
  534. if (version2)
  535. block = Inode2[MINIX_ROOT_INO].i_zone[0];
  536. else
  537. #endif
  538. block = Inode1[MINIX_ROOT_INO].i_zone[0];
  539. read_block(block, blk);
  540. for (size = 16; size < BLOCK_SIZE; size <<= 1) {
  541. if (strcmp(blk + size + 2, "..") == 0) {
  542. dirsize = size;
  543. namelen = size - 2;
  544. return;
  545. }
  546. }
  547. /* use defaults */
  548. }
  549. static void read_superblock(void)
  550. {
  551. xlseek(dev_fd, BLOCK_SIZE, SEEK_SET);
  552. if (BLOCK_SIZE != full_read(dev_fd, superblock_buffer, BLOCK_SIZE))
  553. die("cannot read superblock");
  554. /* already initialized to:
  555. namelen = 14;
  556. dirsize = 16;
  557. version2 = 0;
  558. */
  559. if (MAGIC == MINIX1_SUPER_MAGIC) {
  560. } else if (MAGIC == MINIX1_SUPER_MAGIC2) {
  561. namelen = 30;
  562. dirsize = 32;
  563. #if ENABLE_FEATURE_MINIX2
  564. } else if (MAGIC == MINIX2_SUPER_MAGIC) {
  565. version2 = 1;
  566. } else if (MAGIC == MINIX2_SUPER_MAGIC2) {
  567. namelen = 30;
  568. dirsize = 32;
  569. version2 = 1;
  570. #endif
  571. } else
  572. die("bad magic number in superblock");
  573. if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
  574. die("only 1k blocks/zones supported");
  575. if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
  576. die("bad s_imap_blocks field in superblock");
  577. if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
  578. die("bad s_zmap_blocks field in superblock");
  579. }
  580. static void read_tables(void)
  581. {
  582. inode_map = xzalloc(IMAPS * BLOCK_SIZE);
  583. zone_map = xzalloc(ZMAPS * BLOCK_SIZE);
  584. inode_buffer = xmalloc(INODE_BUFFER_SIZE);
  585. inode_count = xmalloc(INODES + 1);
  586. zone_count = xmalloc(ZONES);
  587. if (IMAPS * BLOCK_SIZE != read(dev_fd, inode_map, IMAPS * BLOCK_SIZE))
  588. die("cannot read inode map");
  589. if (ZMAPS * BLOCK_SIZE != read(dev_fd, zone_map, ZMAPS * BLOCK_SIZE))
  590. die("cannot read zone map");
  591. if (INODE_BUFFER_SIZE != read(dev_fd, inode_buffer, INODE_BUFFER_SIZE))
  592. die("cannot read inodes");
  593. if (NORM_FIRSTZONE != FIRSTZONE) {
  594. printf("warning: firstzone!=norm_firstzone\n");
  595. errors_uncorrected = 1;
  596. }
  597. get_dirsize();
  598. if (OPT_show) {
  599. printf("%u inodes\n"
  600. "%u blocks\n"
  601. "Firstdatazone=%u (%u)\n"
  602. "Zonesize=%u\n"
  603. "Maxsize=%u\n"
  604. "Filesystem state=%u\n"
  605. "namelen=%u\n\n",
  606. INODES,
  607. ZONES,
  608. FIRSTZONE, NORM_FIRSTZONE,
  609. BLOCK_SIZE << ZONESIZE,
  610. MAXSIZE,
  611. Super.s_state,
  612. namelen);
  613. }
  614. }
  615. static void get_inode_common(unsigned nr, uint16_t i_mode)
  616. {
  617. total++;
  618. if (!inode_count[nr]) {
  619. if (!inode_in_use(nr)) {
  620. printf("Inode %d is marked as 'unused', but it is used "
  621. "for file '%s'\n", nr, current_name);
  622. if (OPT_repair) {
  623. if (ask("Mark as 'in use'", 1))
  624. mark_inode(nr);
  625. else
  626. errors_uncorrected = 1;
  627. }
  628. }
  629. if (S_ISDIR(i_mode))
  630. directory++;
  631. else if (S_ISREG(i_mode))
  632. regular++;
  633. else if (S_ISCHR(i_mode))
  634. chardev++;
  635. else if (S_ISBLK(i_mode))
  636. blockdev++;
  637. else if (S_ISLNK(i_mode))
  638. symlinks++;
  639. else if (S_ISSOCK(i_mode));
  640. else if (S_ISFIFO(i_mode));
  641. else {
  642. printf("%s has mode %05o\n", current_name, i_mode);
  643. }
  644. } else
  645. links++;
  646. if (!++inode_count[nr]) {
  647. printf("Warning: inode count too big\n");
  648. inode_count[nr]--;
  649. errors_uncorrected = 1;
  650. }
  651. }
  652. static struct minix1_inode *get_inode(unsigned nr)
  653. {
  654. struct minix1_inode *inode;
  655. if (!nr || nr > INODES)
  656. return NULL;
  657. inode = Inode1 + nr;
  658. get_inode_common(nr, inode->i_mode);
  659. return inode;
  660. }
  661. #if ENABLE_FEATURE_MINIX2
  662. static struct minix2_inode *get_inode2(unsigned nr)
  663. {
  664. struct minix2_inode *inode;
  665. if (!nr || nr > INODES)
  666. return NULL;
  667. inode = Inode2 + nr;
  668. get_inode_common(nr, inode->i_mode);
  669. return inode;
  670. }
  671. #endif
  672. static void check_root(void)
  673. {
  674. struct minix1_inode *inode = Inode1 + MINIX_ROOT_INO;
  675. if (!inode || !S_ISDIR(inode->i_mode))
  676. die("root inode isn't a directory");
  677. }
  678. #if ENABLE_FEATURE_MINIX2
  679. static void check_root2(void)
  680. {
  681. struct minix2_inode *inode = Inode2 + MINIX_ROOT_INO;
  682. if (!inode || !S_ISDIR(inode->i_mode))
  683. die("root inode isn't a directory");
  684. }
  685. #else
  686. void check_root2(void);
  687. #endif
  688. static int add_zone_common(int block, smallint *corrected)
  689. {
  690. if (!block)
  691. return 0;
  692. if (zone_count[block]) {
  693. printf("Already used block is reused in file '%s'. ",
  694. current_name);
  695. if (ask("Clear", 1)) {
  696. block = 0;
  697. *corrected = 1;
  698. return -1; /* "please zero out *znr" */
  699. }
  700. }
  701. if (!zone_in_use(block)) {
  702. printf("Block %d in file '%s' is marked as 'unused'. ",
  703. block, current_name);
  704. if (ask("Correct", 1))
  705. mark_zone(block);
  706. }
  707. if (!++zone_count[block])
  708. zone_count[block]--;
  709. return block;
  710. }
  711. static int add_zone(uint16_t *znr, smallint *corrected)
  712. {
  713. int block;
  714. block = check_zone_nr(znr, corrected);
  715. block = add_zone_common(block, corrected);
  716. if (block == -1) {
  717. *znr = 0;
  718. block = 0;
  719. }
  720. return block;
  721. }
  722. #if ENABLE_FEATURE_MINIX2
  723. static int add_zone2(uint32_t *znr, smallint *corrected)
  724. {
  725. int block;
  726. block = check_zone_nr2(znr, corrected);
  727. block = add_zone_common(block, corrected);
  728. if (block == -1) {
  729. *znr = 0;
  730. block = 0;
  731. }
  732. return block;
  733. }
  734. #endif
  735. static void add_zone_ind(uint16_t *znr, smallint *corrected)
  736. {
  737. int i;
  738. int block;
  739. smallint chg_blk = 0;
  740. block = add_zone(znr, corrected);
  741. if (!block)
  742. return;
  743. read_block(block, add_zone_ind_blk);
  744. for (i = 0; i < (BLOCK_SIZE >> 1); i++)
  745. add_zone(i + (uint16_t *) add_zone_ind_blk, &chg_blk);
  746. if (chg_blk)
  747. write_block(block, add_zone_ind_blk);
  748. }
  749. #if ENABLE_FEATURE_MINIX2
  750. static void add_zone_ind2(uint32_t *znr, smallint *corrected)
  751. {
  752. int i;
  753. int block;
  754. smallint chg_blk = 0;
  755. block = add_zone2(znr, corrected);
  756. if (!block)
  757. return;
  758. read_block(block, add_zone_ind_blk);
  759. for (i = 0; i < BLOCK_SIZE >> 2; i++)
  760. add_zone2(i + (uint32_t *) add_zone_ind_blk, &chg_blk);
  761. if (chg_blk)
  762. write_block(block, add_zone_ind_blk);
  763. }
  764. #endif
  765. static void add_zone_dind(uint16_t *znr, smallint *corrected)
  766. {
  767. int i;
  768. int block;
  769. smallint chg_blk = 0;
  770. block = add_zone(znr, corrected);
  771. if (!block)
  772. return;
  773. read_block(block, add_zone_dind_blk);
  774. for (i = 0; i < (BLOCK_SIZE >> 1); i++)
  775. add_zone_ind(i + (uint16_t *) add_zone_dind_blk, &chg_blk);
  776. if (chg_blk)
  777. write_block(block, add_zone_dind_blk);
  778. }
  779. #if ENABLE_FEATURE_MINIX2
  780. static void add_zone_dind2(uint32_t *znr, smallint *corrected)
  781. {
  782. int i;
  783. int block;
  784. smallint chg_blk = 0;
  785. block = add_zone2(znr, corrected);
  786. if (!block)
  787. return;
  788. read_block(block, add_zone_dind_blk);
  789. for (i = 0; i < BLOCK_SIZE >> 2; i++)
  790. add_zone_ind2(i + (uint32_t *) add_zone_dind_blk, &chg_blk);
  791. if (chg_blk)
  792. write_block(block, add_zone_dind_blk);
  793. }
  794. static void add_zone_tind2(uint32_t *znr, smallint *corrected)
  795. {
  796. int i;
  797. int block;
  798. smallint chg_blk = 0;
  799. block = add_zone2(znr, corrected);
  800. if (!block)
  801. return;
  802. read_block(block, add_zone_tind_blk);
  803. for (i = 0; i < BLOCK_SIZE >> 2; i++)
  804. add_zone_dind2(i + (uint32_t *) add_zone_tind_blk, &chg_blk);
  805. if (chg_blk)
  806. write_block(block, add_zone_tind_blk);
  807. }
  808. #endif
  809. static void check_zones(unsigned i)
  810. {
  811. struct minix1_inode *inode;
  812. if (!i || i > INODES)
  813. return;
  814. if (inode_count[i] > 1) /* have we counted this file already? */
  815. return;
  816. inode = Inode1 + i;
  817. if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
  818. !S_ISLNK(inode->i_mode)) return;
  819. for (i = 0; i < 7; i++)
  820. add_zone(i + inode->i_zone, &changed);
  821. add_zone_ind(7 + inode->i_zone, &changed);
  822. add_zone_dind(8 + inode->i_zone, &changed);
  823. }
  824. #if ENABLE_FEATURE_MINIX2
  825. static void check_zones2(unsigned i)
  826. {
  827. struct minix2_inode *inode;
  828. if (!i || i > INODES)
  829. return;
  830. if (inode_count[i] > 1) /* have we counted this file already? */
  831. return;
  832. inode = Inode2 + i;
  833. if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode)
  834. && !S_ISLNK(inode->i_mode))
  835. return;
  836. for (i = 0; i < 7; i++)
  837. add_zone2(i + inode->i_zone, &changed);
  838. add_zone_ind2(7 + inode->i_zone, &changed);
  839. add_zone_dind2(8 + inode->i_zone, &changed);
  840. add_zone_tind2(9 + inode->i_zone, &changed);
  841. }
  842. #endif
  843. static void check_file(struct minix1_inode *dir, unsigned offset)
  844. {
  845. struct minix1_inode *inode;
  846. int ino;
  847. char *name;
  848. int block;
  849. block = map_block(dir, offset / BLOCK_SIZE);
  850. read_block(block, check_file_blk);
  851. name = check_file_blk + (offset % BLOCK_SIZE) + 2;
  852. ino = *(uint16_t *) (name - 2);
  853. if (ino > INODES) {
  854. printf("%s contains a bad inode number for file '%.*s'. ",
  855. current_name, namelen, name);
  856. if (ask("Remove", 1)) {
  857. *(uint16_t *) (name - 2) = 0;
  858. write_block(block, check_file_blk);
  859. }
  860. ino = 0;
  861. }
  862. push_filename(name);
  863. inode = get_inode(ino);
  864. pop_filename();
  865. if (!offset) {
  866. if (inode && LONE_CHAR(name, '.'))
  867. return;
  868. printf("%s: bad directory: '.' isn't first\n", current_name);
  869. errors_uncorrected = 1;
  870. }
  871. if (offset == dirsize) {
  872. if (inode && strcmp("..", name) == 0)
  873. return;
  874. printf("%s: bad directory: '..' isn't second\n", current_name);
  875. errors_uncorrected = 1;
  876. }
  877. if (!inode)
  878. return;
  879. push_filename(name);
  880. if (OPT_list) {
  881. if (OPT_verbose)
  882. printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
  883. printf("%s%s\n", current_name, S_ISDIR(inode->i_mode) ? ":" : "");
  884. }
  885. check_zones(ino);
  886. if (inode && S_ISDIR(inode->i_mode))
  887. recursive_check(ino);
  888. pop_filename();
  889. }
  890. #if ENABLE_FEATURE_MINIX2
  891. static void check_file2(struct minix2_inode *dir, unsigned offset)
  892. {
  893. struct minix2_inode *inode;
  894. int ino;
  895. char *name;
  896. int block;
  897. block = map_block2(dir, offset / BLOCK_SIZE);
  898. read_block(block, check_file_blk);
  899. name = check_file_blk + (offset % BLOCK_SIZE) + 2;
  900. ino = *(uint16_t *) (name - 2);
  901. if (ino > INODES) {
  902. printf("%s contains a bad inode number for file '%.*s'. ",
  903. current_name, namelen, name);
  904. if (ask("Remove", 1)) {
  905. *(uint16_t *) (name - 2) = 0;
  906. write_block(block, check_file_blk);
  907. }
  908. ino = 0;
  909. }
  910. push_filename(name);
  911. inode = get_inode2(ino);
  912. pop_filename();
  913. if (!offset) {
  914. if (inode && LONE_CHAR(name, '.'))
  915. return;
  916. printf("%s: bad directory: '.' isn't first\n", current_name);
  917. errors_uncorrected = 1;
  918. }
  919. if (offset == dirsize) {
  920. if (inode && strcmp("..", name) == 0)
  921. return;
  922. printf("%s: bad directory: '..' isn't second\n", current_name);
  923. errors_uncorrected = 1;
  924. }
  925. if (!inode)
  926. return;
  927. push_filename(name);
  928. if (OPT_list) {
  929. if (OPT_verbose)
  930. printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
  931. printf("%s%s\n", current_name, S_ISDIR(inode->i_mode) ? ":" : "");
  932. }
  933. check_zones2(ino);
  934. if (inode && S_ISDIR(inode->i_mode))
  935. recursive_check2(ino);
  936. pop_filename();
  937. }
  938. #endif
  939. static void recursive_check(unsigned ino)
  940. {
  941. struct minix1_inode *dir;
  942. unsigned offset;
  943. dir = Inode1 + ino;
  944. if (!S_ISDIR(dir->i_mode))
  945. die("internal error");
  946. if (dir->i_size < 2 * dirsize) {
  947. printf("%s: bad directory: size<32", current_name);
  948. errors_uncorrected = 1;
  949. }
  950. for (offset = 0; offset < dir->i_size; offset += dirsize)
  951. check_file(dir, offset);
  952. }
  953. #if ENABLE_FEATURE_MINIX2
  954. static void recursive_check2(unsigned ino)
  955. {
  956. struct minix2_inode *dir;
  957. unsigned offset;
  958. dir = Inode2 + ino;
  959. if (!S_ISDIR(dir->i_mode))
  960. die("internal error");
  961. if (dir->i_size < 2 * dirsize) {
  962. printf("%s: bad directory: size<32", current_name);
  963. errors_uncorrected = 1;
  964. }
  965. for (offset = 0; offset < dir->i_size; offset += dirsize)
  966. check_file2(dir, offset);
  967. }
  968. #endif
  969. static int bad_zone(int i)
  970. {
  971. char buffer[BLOCK_SIZE];
  972. xlseek(dev_fd, BLOCK_SIZE * i, SEEK_SET);
  973. return (BLOCK_SIZE != full_read(dev_fd, buffer, BLOCK_SIZE));
  974. }
  975. static void check_counts(void)
  976. {
  977. int i;
  978. for (i = 1; i <= INODES; i++) {
  979. if (OPT_warn_mode && Inode1[i].i_mode && !inode_in_use(i)) {
  980. printf("Inode %d has non-zero mode. ", i);
  981. if (ask("Clear", 1)) {
  982. Inode1[i].i_mode = 0;
  983. changed = 1;
  984. }
  985. }
  986. if (!inode_count[i]) {
  987. if (!inode_in_use(i))
  988. continue;
  989. printf("Unused inode %d is marked as 'used' in the bitmap. ", i);
  990. if (ask("Clear", 1))
  991. unmark_inode(i);
  992. continue;
  993. }
  994. if (!inode_in_use(i)) {
  995. printf("Inode %d is used, but marked as 'unused' in the bitmap. ", i);
  996. if (ask("Set", 1))
  997. mark_inode(i);
  998. }
  999. if (Inode1[i].i_nlinks != inode_count[i]) {
  1000. printf("Inode %d (mode=%07o), i_nlinks=%d, counted=%d. ",
  1001. i, Inode1[i].i_mode, Inode1[i].i_nlinks,
  1002. inode_count[i]);
  1003. if (ask("Set i_nlinks to count", 1)) {
  1004. Inode1[i].i_nlinks = inode_count[i];
  1005. changed = 1;
  1006. }
  1007. }
  1008. }
  1009. for (i = FIRSTZONE; i < ZONES; i++) {
  1010. if ((zone_in_use(i) != 0) == zone_count[i])
  1011. continue;
  1012. if (!zone_count[i]) {
  1013. if (bad_zone(i))
  1014. continue;
  1015. printf("Zone %d is marked 'in use', but no file uses it. ", i);
  1016. if (ask("Unmark", 1))
  1017. unmark_zone(i);
  1018. continue;
  1019. }
  1020. printf("Zone %d: %sin use, counted=%d\n",
  1021. i, zone_in_use(i) ? "" : "not ", zone_count[i]);
  1022. }
  1023. }
  1024. #if ENABLE_FEATURE_MINIX2
  1025. static void check_counts2(void)
  1026. {
  1027. int i;
  1028. for (i = 1; i <= INODES; i++) {
  1029. if (OPT_warn_mode && Inode2[i].i_mode && !inode_in_use(i)) {
  1030. printf("Inode %d has non-zero mode. ", i);
  1031. if (ask("Clear", 1)) {
  1032. Inode2[i].i_mode = 0;
  1033. changed = 1;
  1034. }
  1035. }
  1036. if (!inode_count[i]) {
  1037. if (!inode_in_use(i))
  1038. continue;
  1039. printf("Unused inode %d is marked as 'used' in the bitmap. ", i);
  1040. if (ask("Clear", 1))
  1041. unmark_inode(i);
  1042. continue;
  1043. }
  1044. if (!inode_in_use(i)) {
  1045. printf("Inode %d is used, but marked as 'unused' in the bitmap. ", i);
  1046. if (ask("Set", 1))
  1047. mark_inode(i);
  1048. }
  1049. if (Inode2[i].i_nlinks != inode_count[i]) {
  1050. printf("Inode %d (mode=%07o), i_nlinks=%d, counted=%d. ",
  1051. i, Inode2[i].i_mode, Inode2[i].i_nlinks,
  1052. inode_count[i]);
  1053. if (ask("Set i_nlinks to count", 1)) {
  1054. Inode2[i].i_nlinks = inode_count[i];
  1055. changed = 1;
  1056. }
  1057. }
  1058. }
  1059. for (i = FIRSTZONE; i < ZONES; i++) {
  1060. if ((zone_in_use(i) != 0) == zone_count[i])
  1061. continue;
  1062. if (!zone_count[i]) {
  1063. if (bad_zone(i))
  1064. continue;
  1065. printf("Zone %d is marked 'in use', but no file uses it. ", i);
  1066. if (ask("Unmark", 1))
  1067. unmark_zone(i);
  1068. continue;
  1069. }
  1070. printf("Zone %d: %sin use, counted=%d\n",
  1071. i, zone_in_use(i) ? "" : "not ", zone_count[i]);
  1072. }
  1073. }
  1074. #endif
  1075. static void check(void)
  1076. {
  1077. memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
  1078. memset(zone_count, 0, ZONES * sizeof(*zone_count));
  1079. check_zones(MINIX_ROOT_INO);
  1080. recursive_check(MINIX_ROOT_INO);
  1081. check_counts();
  1082. }
  1083. #if ENABLE_FEATURE_MINIX2
  1084. static void check2(void)
  1085. {
  1086. memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
  1087. memset(zone_count, 0, ZONES * sizeof(*zone_count));
  1088. check_zones2(MINIX_ROOT_INO);
  1089. recursive_check2(MINIX_ROOT_INO);
  1090. check_counts2();
  1091. }
  1092. #else
  1093. void check2(void);
  1094. #endif
  1095. int fsck_minix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  1096. int fsck_minix_main(int argc UNUSED_PARAM, char **argv)
  1097. {
  1098. struct termios tmp;
  1099. int retcode = 0;
  1100. xfunc_error_retval = 8;
  1101. INIT_G();
  1102. opt_complementary = "=1:ar"; /* one argument; -a assumes -r */
  1103. getopt32(argv, OPTION_STR);
  1104. argv += optind;
  1105. device_name = argv[0];
  1106. check_mount(); /* trying to check a mounted filesystem? */
  1107. if (OPT_manual) {
  1108. if (!isatty(0) || !isatty(1))
  1109. die("need terminal for interactive repairs");
  1110. }
  1111. xmove_fd(xopen(device_name, OPT_repair ? O_RDWR : O_RDONLY), dev_fd);
  1112. /*sync(); paranoia? */
  1113. read_superblock();
  1114. /*
  1115. * Determine whether or not we should continue with the checking.
  1116. * This is based on the status of the filesystem valid and error
  1117. * flags and whether or not the -f switch was specified on the
  1118. * command line.
  1119. */
  1120. printf("%s: %s\n", applet_name, bb_banner);
  1121. if (!(Super.s_state & MINIX_ERROR_FS)
  1122. && (Super.s_state & MINIX_VALID_FS) && !OPT_force
  1123. ) {
  1124. if (OPT_repair)
  1125. printf("%s is clean, check is skipped\n", device_name);
  1126. return 0;
  1127. } else if (OPT_force)
  1128. printf("Forcing filesystem check on %s\n", device_name);
  1129. else if (OPT_repair)
  1130. printf("Filesystem on %s is dirty, needs checking\n",
  1131. device_name);
  1132. read_tables();
  1133. if (OPT_manual) {
  1134. tcgetattr(0, &sv_termios);
  1135. tmp = sv_termios;
  1136. tmp.c_lflag &= ~(ICANON | ECHO);
  1137. tcsetattr_stdin_TCSANOW(&tmp);
  1138. termios_set = 1;
  1139. }
  1140. if (version2) {
  1141. check_root2();
  1142. check2();
  1143. } else {
  1144. check_root();
  1145. check();
  1146. }
  1147. if (OPT_verbose) {
  1148. int i, free_cnt;
  1149. for (i = 1, free_cnt = 0; i <= INODES; i++)
  1150. if (!inode_in_use(i))
  1151. free_cnt++;
  1152. printf("\n%6u inodes used (%u%%)\n", (INODES - free_cnt),
  1153. 100 * (INODES - free_cnt) / INODES);
  1154. for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++)
  1155. if (!zone_in_use(i))
  1156. free_cnt++;
  1157. printf("%6u zones used (%u%%)\n\n"
  1158. "%6u regular files\n"
  1159. "%6u directories\n"
  1160. "%6u character device files\n"
  1161. "%6u block device files\n"
  1162. "%6u links\n"
  1163. "%6u symbolic links\n"
  1164. "------\n"
  1165. "%6u files\n",
  1166. (ZONES - free_cnt), 100 * (ZONES - free_cnt) / ZONES,
  1167. regular, directory, chardev, blockdev,
  1168. links - 2 * directory + 1, symlinks,
  1169. total - 2 * directory + 1);
  1170. }
  1171. if (changed) {
  1172. write_tables();
  1173. printf("FILE SYSTEM HAS BEEN CHANGED\n");
  1174. sync();
  1175. } else if (OPT_repair)
  1176. write_superblock();
  1177. if (OPT_manual)
  1178. tcsetattr_stdin_TCSANOW(&sv_termios);
  1179. if (changed)
  1180. retcode += 3;
  1181. if (errors_uncorrected)
  1182. retcode += 4;
  1183. return retcode;
  1184. }