~vcs-imports/busybox/trunk

« back to all changes in this revision

Viewing changes to fsck_minix.c

  • Committer: Eric Andersen
  • Date: 1999-11-24 09:04:33 UTC
  • Revision ID: git-v1:b99df0fd65abe3245fa2d04115326100847f865e
First draft

Show diffs side-by-side

added added

removed removed

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