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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 13 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
Line 
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/*
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>
91#include "libbb.h"
92#include "minix.h"
93
94#ifndef BLKGETSIZE
95#define BLKGETSIZE _IO(0x12,96)    /* return device size */
96#endif
97
98enum {
99#ifdef UNUSED
100    MINIX1_LINK_MAX = 250,
101    MINIX2_LINK_MAX = 65530,
102    MINIX_I_MAP_SLOTS = 8,
103    MINIX_Z_MAP_SLOTS = 64,
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};
109
110#if !ENABLE_FEATURE_MINIX2
111enum { version2 = 0 };
112#endif
113
114enum { MAX_DEPTH = 32 };
115
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;
130
131    char *inode_map;
132    char *zone_map;
133
134    unsigned char *inode_count;
135    unsigned char *zone_count;
136
137    /* File-name data */
138    int name_depth;
139    char *name_component[MAX_DEPTH+1];
140
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];
148
149    /* File-name data */
150    char current_name[MAX_DEPTH * MINIX_NAME_MAX];
151};
152
153#define G (*ptr_to_globals)
154#define dev_fd             (G.dev_fd             )
155#if ENABLE_FEATURE_MINIX2
156#define version2           (G.version2           )
157#endif
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)
200
201#define Inode1 (((struct minix1_inode *) inode_buffer)-1)
202#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
203
204#define Super (*(struct minix_super_block *)(super_block_buffer))
205
206#if ENABLE_FEATURE_MINIX2
207# define ZONES    ((unsigned)(version2 ? Super.s_zones : Super.s_nzones))
208#else
209# define ZONES    ((unsigned)(Super.s_nzones))
210#endif
211#define INODES    ((unsigned)Super.s_ninodes)
212#define IMAPS     ((unsigned)Super.s_imap_blocks)
213#define ZMAPS     ((unsigned)Super.s_zmap_blocks)
214#define FIRSTZONE ((unsigned)Super.s_firstdatazone)
215#define ZONESIZE  ((unsigned)Super.s_log_zone_size)
216#define MAXSIZE   ((unsigned)Super.s_max_size)
217#define MAGIC     (Super.s_magic)
218
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}
224
225#if ENABLE_FEATURE_MINIX2
226#define INODE_BLOCKS div_roundup(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
227                    : MINIX1_INODES_PER_BLOCK))
228#else
229#define INODE_BLOCKS div_roundup(INODES, MINIX1_INODES_PER_BLOCK)
230#endif
231
232#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
233#define NORM_FIRSTZONE    (2 + IMAPS + ZMAPS + INODE_BLOCKS)
234
235/* Before you ask "where they come from?": */
236/* setbit/clrbit are supplied by sys/param.h */
237
238static int minix_bit(const char *a, unsigned i)
239{
240    return (a[i >> 3] & (1<<(i & 7)));
241}
242
243static void minix_setbit(char *a, unsigned i)
244{
245    setbit(a, i);
246    changed = 1;
247}
248static void minix_clrbit(char *a, unsigned i)
249{
250    clrbit(a, i);
251    changed = 1;
252}
253
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)))
257
258#define mark_inode(x)   (minix_setbit(inode_map,(x)))
259#define unmark_inode(x) (minix_clrbit(inode_map,(x)))
260
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)
272{
273    if (termios_set)
274        tcsetattr(0, TCSANOW, &sv_termios);
275    bb_error_msg_and_die("%s", str);
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
293static void pop_filename(void)
294{
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) {
310        puts("");
311        errors_uncorrected = 1;
312        return 0;
313    }
314    if (automatic) {
315        puts("");
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);
323        c = getchar();
324        if (c == EOF) {
325            if (!def)
326                errors_uncorrected = 1;
327            return def;
328        }
329        c = toupper(c);
330        if (c == 'Y') {
331            def = 1;
332            break;
333        } else if (c == 'N') {
334            def = 0;
335            break;
336        } else if (c == ' ' || c == '\n')
337            break;
338    }
339    if (def)
340        printf("y\n");
341    else {
342        printf("n\n");
343        errors_uncorrected = 1;
344    }
345    return def;
346}
347
348/*
349 * Make certain that we aren't checking a filesystem that is on a
350 * mounted partition.  Code adapted from e2fsck, Copyright (C) 1993,
351 * 1994 Theodore Ts'o.  Also licensed under GPL.
352 */
353static void check_mount(void)
354{
355    FILE *f;
356    struct mntent *mnt;
357    int cont;
358    int fd;
359
360    f = setmntent(MOUNTED, "r");
361    if (f == NULL)
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;
378    close(fd);
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 */
396static int check_zone_nr2(uint32_t *nr, smallint *corrected)
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
415static int check_zone_nr(uint16_t *nr, smallint *corrected)
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 */
426static void read_block(unsigned nr, char *addr)
427{
428    if (!nr) {
429        memset(addr, 0, BLOCK_SIZE);
430        return;
431    }
432    if (BLOCK_SIZE * nr != lseek(dev_fd, BLOCK_SIZE * nr, SEEK_SET)) {
433        printf("%s: cannot seek to block in file '%s'\n",
434                bb_msg_read_error, current_name);
435        errors_uncorrected = 1;
436        memset(addr, 0, BLOCK_SIZE);
437    } else if (BLOCK_SIZE != read(dev_fd, addr, BLOCK_SIZE)) {
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 */
448static void write_block(unsigned nr, char *addr)
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    }
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)) {
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 */
472static int map_block(struct minix1_inode *inode, unsigned blknr)
473{
474    uint16_t ind[BLOCK_SIZE >> 1];
475    uint16_t dind[BLOCK_SIZE >> 1];
476    int block, result;
477    smallint blk_chg;
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
507#if ENABLE_FEATURE_MINIX2
508static int map_block2(struct minix2_inode *inode, unsigned blknr)
509{
510    uint32_t ind[BLOCK_SIZE >> 2];
511    uint32_t dind[BLOCK_SIZE >> 2];
512    uint32_t tind[BLOCK_SIZE >> 2];
513    int block, result;
514    smallint blk_chg;
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     */
574    Super.s_state |= MINIX_VALID_FS | MINIX_ERROR_FS;
575    if (!errors_uncorrected)
576        Super.s_state &= ~MINIX_ERROR_FS;
577
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");
582}
583
584static void write_tables(void)
585{
586    write_super_block();
587
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");
594}
595
596static void get_dirsize(void)
597{
598    int block;
599    char blk[BLOCK_SIZE];
600    int size;
601
602#if ENABLE_FEATURE_MINIX2
603    if (version2)
604        block = Inode2[MINIX_ROOT_INO].i_zone[0];
605    else
606#endif
607        block = Inode1[MINIX_ROOT_INO].i_zone[0];
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{
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");
625    /* already initialized to:
626    namelen = 14;
627    dirsize = 16;
628    version2 = 0;
629    */
630    if (MAGIC == MINIX1_SUPER_MAGIC) {
631    } else if (MAGIC == MINIX1_SUPER_MAGIC2) {
632        namelen = 30;
633        dirsize = 32;
634#if ENABLE_FEATURE_MINIX2
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
643        die("bad magic number in super-block");
644    if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
645        die("only 1k blocks/zones supported");
646    if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
647        die("bad s_imap_blocks field in super-block");
648    if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
649        die("bad s_zmap_blocks field in super-block");
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);
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");
665    if (NORM_FIRSTZONE != FIRSTZONE) {
666        printf("warning: firstzone!=norm_firstzone\n");
667        errors_uncorrected = 1;
668    }
669    get_dirsize();
670    if (show) {
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",
678            INODES,
679            ZONES,
680            FIRSTZONE, NORM_FIRSTZONE,
681            BLOCK_SIZE << ZONESIZE,
682            MAXSIZE,
683            Super.s_state,
684            namelen);
685    }
686}
687
688static struct minix1_inode *get_inode(unsigned nr)
689{
690    struct minix1_inode *inode;
691
692    if (!nr || nr > INODES)
693        return NULL;
694    total++;
695    inode = Inode1 + nr;
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);
703                else
704                    errors_uncorrected = 1;
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
733#if ENABLE_FEATURE_MINIX2
734static struct minix2_inode *get_inode2(unsigned nr)
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{
781    struct minix1_inode *inode = Inode1 + MINIX_ROOT_INO;
782
783    if (!inode || !S_ISDIR(inode->i_mode))
784        die("root inode isn't a directory");
785}
786
787#if ENABLE_FEATURE_MINIX2
788static void check_root2(void)
789{
790    struct minix2_inode *inode = Inode2 + MINIX_ROOT_INO;
791
792    if (!inode || !S_ISDIR(inode->i_mode))
793        die("root inode isn't a directory");
794}
795#else
796void check_root2(void);
797#endif
798
799static int add_zone(uint16_t *znr, smallint *corrected)
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
829#if ENABLE_FEATURE_MINIX2
830static int add_zone2(uint32_t *znr, smallint *corrected)
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
861static void add_zone_ind(uint16_t *znr, smallint *corrected)
862{
863    int i;
864    int block;
865    smallint chg_blk = 0;
866
867    block = add_zone(znr, corrected);
868    if (!block)
869        return;
870    read_block(block, add_zone_ind_blk);
871    for (i = 0; i < (BLOCK_SIZE >> 1); i++)
872        add_zone(i + (uint16_t *) add_zone_ind_blk, &chg_blk);
873    if (chg_blk)
874        write_block(block, add_zone_ind_blk);
875}
876
877#if ENABLE_FEATURE_MINIX2
878static void add_zone_ind2(uint32_t *znr, smallint *corrected)
879{
880    int i;
881    int block;
882    smallint chg_blk = 0;
883
884    block = add_zone2(znr, corrected);
885    if (!block)
886        return;
887    read_block(block, add_zone_ind_blk);
888    for (i = 0; i < BLOCK_SIZE >> 2; i++)
889        add_zone2(i + (uint32_t *) add_zone_ind_blk, &chg_blk);
890    if (chg_blk)
891        write_block(block, add_zone_ind_blk);
892}
893#endif
894
895static void add_zone_dind(uint16_t *znr, smallint *corrected)
896{
897    int i;
898    int block;
899    smallint chg_blk = 0;
900
901    block = add_zone(znr, corrected);
902    if (!block)
903        return;
904    read_block(block, add_zone_dind_blk);
905    for (i = 0; i < (BLOCK_SIZE >> 1); i++)
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);
909}
910
911#if ENABLE_FEATURE_MINIX2
912static void add_zone_dind2(uint32_t *znr, smallint *corrected)
913{
914    int i;
915    int block;
916    smallint chg_blk = 0;
917
918    block = add_zone2(znr, corrected);
919    if (!block)
920        return;
921    read_block(block, add_zone_dind_blk);
922    for (i = 0; i < BLOCK_SIZE >> 2; i++)
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);
926}
927
928static void add_zone_tind2(uint32_t *znr, smallint *corrected)
929{
930    int i;
931    int block;
932    smallint chg_blk = 0;
933
934    block = add_zone2(znr, corrected);
935    if (!block)
936        return;
937    read_block(block, add_zone_tind_blk);
938    for (i = 0; i < BLOCK_SIZE >> 2; i++)
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);
942}
943#endif
944
945static void check_zones(unsigned i)
946{
947    struct minix1_inode *inode;
948
949    if (!i || i > INODES)
950        return;
951    if (inode_count[i] > 1)     /* have we counted this file already? */
952        return;
953    inode = Inode1 + i;
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
962#if ENABLE_FEATURE_MINIX2
963static void check_zones2(unsigned i)
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
983static void check_file(struct minix1_inode *dir, unsigned offset)
984{
985    struct minix1_inode *inode;
986    int ino;
987    char *name;
988    int block;
989
990    block = map_block(dir, offset / BLOCK_SIZE);
991    read_block(block, check_file_blk);
992    name = check_file_blk + (offset % BLOCK_SIZE) + 2;
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;
999            write_block(block, check_file_blk);
1000        }
1001        ino = 0;
1002    }
1003    push_filename(name);
1004    inode = get_inode(ino);
1005    pop_filename();
1006    if (!offset) {
1007        if (inode && LONE_CHAR(name, '.'))
1008            return;
1009        printf("%s: bad directory: '.' isn't first\n", current_name);
1010        errors_uncorrected = 1;
1011    }
1012    if (offset == dirsize) {
1013        if (inode && strcmp("..", name) == 0)
1014            return;
1015        printf("%s: bad directory: '..' isn't second\n", current_name);
1016        errors_uncorrected = 1;
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
1032#if ENABLE_FEATURE_MINIX2
1033static void check_file2(struct minix2_inode *dir, unsigned offset)
1034{
1035    struct minix2_inode *inode;
1036    int ino;
1037    char *name;
1038    int block;
1039
1040    block = map_block2(dir, offset / BLOCK_SIZE);
1041    read_block(block, check_file_blk);
1042    name = check_file_blk + (offset % BLOCK_SIZE) + 2;
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;
1049            write_block(block, check_file_blk);
1050        }
1051        ino = 0;
1052    }
1053    push_filename(name);
1054    inode = get_inode2(ino);
1055    pop_filename();
1056    if (!offset) {
1057        if (inode && LONE_CHAR(name, '.'))
1058            return;
1059        printf("%s: bad directory: '.' isn't first\n", current_name);
1060        errors_uncorrected = 1;
1061    }
1062    if (offset == dirsize) {
1063        if (inode && strcmp("..", name) == 0)
1064            return;
1065        printf("%s: bad directory: '..' isn't second\n", current_name);
1066        errors_uncorrected = 1;
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
1083static void recursive_check(unsigned ino)
1084{
1085    struct minix1_inode *dir;
1086    unsigned offset;
1087
1088    dir = Inode1 + ino;
1089    if (!S_ISDIR(dir->i_mode))
1090        die("internal error");
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
1099#if ENABLE_FEATURE_MINIX2
1100static void recursive_check2(unsigned ino)
1101{
1102    struct minix2_inode *dir;
1103    unsigned offset;
1104
1105    dir = Inode2 + ino;
1106    if (!S_ISDIR(dir->i_mode))
1107        die("internal error");
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{
1119    char buffer[BLOCK_SIZE];
1120
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));
1124}
1125
1126static void check_counts(void)
1127{
1128    int i;
1129
1130    for (i = 1; i <= INODES; i++) {
1131        if (warn_mode && Inode1[i].i_mode && !inode_in_use(i)) {
1132            printf("Inode %d has non-zero mode. ", i);
1133            if (ask("Clear", 1)) {
1134                Inode1[i].i_mode = 0;
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        }
1151        if (Inode1[i].i_nlinks != inode_count[i]) {
1152            printf("Inode %d (mode=%07o), i_nlinks=%d, counted=%d. ",
1153                i, Inode1[i].i_mode, Inode1[i].i_nlinks,
1154                inode_count[i]);
1155            if (ask("Set i_nlinks to count", 1)) {
1156                Inode1[i].i_nlinks = inode_count[i];
1157                changed = 1;
1158            }
1159        }
1160    }
1161    for (i = FIRSTZONE; i < ZONES; i++) {
1162        if ((zone_in_use(i) != 0) == zone_count[i])
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
1177#if ENABLE_FEATURE_MINIX2
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. ",
1205                i, Inode2[i].i_mode, Inode2[i].i_nlinks,
1206                inode_count[i]);
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++) {
1214        if ((zone_in_use(i) != 0) == zone_count[i])
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));
1234    check_zones(MINIX_ROOT_INO);
1235    recursive_check(MINIX_ROOT_INO);
1236    check_counts();
1237}
1238
1239#if ENABLE_FEATURE_MINIX2
1240static void check2(void)
1241{
1242    memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
1243    memset(zone_count, 0, ZONES * sizeof(*zone_count));
1244    check_zones2(MINIX_ROOT_INO);
1245    recursive_check2(MINIX_ROOT_INO);
1246    check_counts2();
1247}
1248#else
1249void check2(void);
1250#endif
1251
1252int fsck_minix_main(int argc, char **argv);
1253int fsck_minix_main(int argc, char **argv)
1254{
1255    struct termios tmp;
1256    int retcode = 0;
1257
1258    xfunc_error_retval = 8;
1259
1260    INIT_G();
1261
1262    if (INODE_SIZE1 * MINIX1_INODES_PER_BLOCK != BLOCK_SIZE)
1263        die("bad inode size");
1264#if ENABLE_FEATURE_MINIX2
1265    if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
1266        die("bad v2 inode size");
1267#endif
1268    while (--argc != 0) {
1269        argv++;
1270        if (argv[0][0] != '-') {
1271            if (device_name)
1272                bb_show_usage();
1273            device_name = argv[0];
1274        } else {
1275            while (*++argv[0]) {
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                }
1303            }
1304        }
1305    }
1306    if (!device_name)
1307        bb_show_usage();
1308
1309    check_mount();              /* trying to check a mounted filesystem? */
1310    if (repair && !automatic) {
1311        if (!isatty(0) || !isatty(1))
1312            die("need terminal for interactive repairs");
1313    }
1314    dev_fd = xopen(device_name, repair ? O_RDWR : O_RDONLY);
1315
1316    /*sync(); paranoia? */
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     */
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    ) {
1330        if (repair)
1331            printf("%s is clean, check is skipped\n", device_name);
1332        return 0;
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) {
1342        tcgetattr(0, &sv_termios);
1343        tmp = sv_termios;
1344        tmp.c_lflag &= ~(ICANON | ECHO);
1345        tcsetattr(0, TCSANOW, &tmp);
1346        termios_set = 1;
1347    }
1348
1349    if (version2) {
1350        check_root2();
1351        check2();
1352    } else {
1353        check_root();
1354        check();
1355    }
1356
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++;
1363        printf("\n%6u inodes used (%u%%)\n", (INODES - free_cnt),
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++;
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"
1375               "------\n"
1376               "%6u files\n",
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)
1390        tcsetattr(0, TCSANOW, &sv_termios);
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.