source: MondoRescue/branches/stable/mindi-busybox/util-linux/fsck_minix.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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