fsck_minix.c 34 KB

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