blob: 084c76d36cd5ee31c612e75b2fb9ac344d110023 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersene494fdd1999-10-19 20:23:03 +00002/*
3 * fsck.c - a file system consistency checker for Linux.
4 *
5 * (C) 1991, 1992 Linus Torvalds. This file may be redistributed
6 * as per the GNU copyleft.
7 */
8
9/*
10 * 09.11.91 - made the first rudimetary functions
11 *
12 * 10.11.91 - updated, does checking, no repairs yet.
13 * Sent out to the mailing-list for testing.
14 *
15 * 14.11.91 - Testing seems to have gone well. Added some
16 * correction-code, and changed some functions.
17 *
18 * 15.11.91 - More correction code. Hopefully it notices most
19 * cases now, and tries to do something about them.
20 *
21 * 16.11.91 - More corrections (thanks to Mika Jalava). Most
22 * things seem to work now. Yeah, sure.
23 *
24 *
25 * 19.04.92 - Had to start over again from this old version, as a
26 * kernel bug ate my enhanced fsck in february.
27 *
28 * 28.02.93 - added support for different directory entry sizes..
29 *
30 * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with
31 * super-block information
32 *
33 * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform
34 * to that required by fsutil
35 *
36 * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu)
37 * Added support for file system valid flag. Also
38 * added program_version variable and output of
39 * program name and version number when program
40 * is executed.
41 *
42 * 30.10.94 - added support for v2 filesystem
43 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
44 *
45 * 10.12.94 - added test to prevent checking of mounted fs adapted
46 * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck
47 * program. (Daniel Quinlan, quinlan@yggdrasil.com)
48 *
49 * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such
50 * for modern libcs (janl@math.uio.no, Nicolai Langfeldt)
51 *
52 * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk
53 * (Russell King). He made them for ARM. It would seem
54 * that the ARM is powerful enough to do this in C whereas
55 * i386 and m64k must use assembly to get it fast >:-)
56 * This should make minix fsck systemindependent.
57 * (janl@math.uio.no, Nicolai Langfeldt)
58 *
59 * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler
60 * warnings. Added mc68k bitops from
61 * Joerg Dorchain <dorchain@mpi-sb.mpg.de>.
62 *
63 * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by
64 * Andreas Schwab.
65 *
66 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
67 * - added Native Language Support
68 *
69 *
70 * I've had no time to add comments - hopefully the function names
71 * are comments enough. As with all file system checkers, this assumes
72 * the file system is quiescent - don't use it on a mounted device
73 * unless you can be sure nobody is writing to it (and remember that the
74 * kernel can write to it when it searches for files).
75 *
76 * Usuage: fsck [-larvsm] device
77 * -l for a listing of all the filenames
78 * -a for automatic repairs (not implemented)
79 * -r for repairs (interactive) (not implemented)
80 * -v for verbose (tells how many files)
81 * -s for super-block info
82 * -m for minix-like "mode not cleared" warnings
83 * -f force filesystem check even if filesystem marked as valid
84 *
85 * The device may be a block device or a image of one, but this isn't
86 * enforced (but it's not much fun on a character device :-).
87 */
88
Eric Andersene674eb71999-10-19 20:52:57 +000089#include "internal.h"
Eric Andersene494fdd1999-10-19 20:23:03 +000090#include <stdio.h>
91#include <errno.h>
92#include <unistd.h>
93#include <string.h>
94#include <fcntl.h>
95#include <ctype.h>
96#include <stdlib.h>
97#include <termios.h>
98#include <mntent.h>
99#include <sys/stat.h>
Erik Andersene49d5ec2000-02-08 19:58:47 +0000100#include <sys/param.h> /* for PATH_MAX */
Eric Andersene494fdd1999-10-19 20:23:03 +0000101
102#include <linux/fs.h>
103#include <linux/minix_fs.h>
Eric Andersene494fdd1999-10-19 20:23:03 +0000104
105#ifdef MINIX2_SUPER_MAGIC2
106#define HAVE_MINIX2 1
107#endif
108
109#ifndef __linux__
110#define volatile
111#endif
112
113#define ROOT_INO 1
114
115#define UPPER(size,n) ((size+((n)-1))/(n))
116#define INODE_SIZE (sizeof(struct minix_inode))
117#ifdef HAVE_MINIX2
118#define INODE_SIZE2 (sizeof(struct minix2_inode))
119#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
120 : MINIX_INODES_PER_BLOCK))
121#else
122#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
123#endif
124#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
125
126#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
127
Erik Andersene49d5ec2000-02-08 19:58:47 +0000128static char *program_name = "fsck.minix";
129static char *program_version = "1.2 - 11/11/96";
130static char *device_name = NULL;
Eric Andersene494fdd1999-10-19 20:23:03 +0000131static int IN;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000132static int repair = 0, automatic = 0, verbose = 0, list = 0, show =
133 0, warn_mode = 0, force = 0;
134static int directory = 0, regular = 0, blockdev = 0, chardev = 0, links =
135 0, symlinks = 0, total = 0;
Eric Andersene494fdd1999-10-19 20:23:03 +0000136
Erik Andersene49d5ec2000-02-08 19:58:47 +0000137static int changed = 0; /* flags if the filesystem has been changed */
138static int errors_uncorrected = 0; /* flag if some error was not corrected */
Eric Andersene494fdd1999-10-19 20:23:03 +0000139static int dirsize = 16;
140static int namelen = 14;
141static int version2 = 0;
142static struct termios termios;
143static int termios_set = 0;
144
145/* File-name data */
146#define MAX_DEPTH 50
147static int name_depth = 0;
Erik Andersenfac10d72000-02-07 05:29:42 +0000148static char name_list[MAX_DEPTH][PATH_MAX + 1];
Eric Andersene494fdd1999-10-19 20:23:03 +0000149
Erik Andersene49d5ec2000-02-08 19:58:47 +0000150static char *inode_buffer = NULL;
151
Eric Andersene494fdd1999-10-19 20:23:03 +0000152#define Inode (((struct minix_inode *) inode_buffer)-1)
153#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
154static char super_block_buffer[BLOCK_SIZE];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000155
Eric Andersene494fdd1999-10-19 20:23:03 +0000156#define Super (*(struct minix_super_block *)super_block_buffer)
157#define INODES ((unsigned long)Super.s_ninodes)
158#ifdef HAVE_MINIX2
159#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
160#else
161#define ZONES ((unsigned long)(Super.s_nzones))
162#endif
163#define IMAPS ((unsigned long)Super.s_imap_blocks)
164#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
165#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
166#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
167#define MAXSIZE ((unsigned long)Super.s_max_size)
168#define MAGIC (Super.s_magic)
169#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
170
171static char *inode_map;
172static char *zone_map;
173
Erik Andersene49d5ec2000-02-08 19:58:47 +0000174static unsigned char *inode_count = NULL;
175static unsigned char *zone_count = NULL;
Eric Andersene494fdd1999-10-19 20:23:03 +0000176
Eric Andersene674eb71999-10-19 20:52:57 +0000177static void recursive_check(unsigned int ino);
178static void recursive_check2(unsigned int ino);
Eric Andersene494fdd1999-10-19 20:23:03 +0000179
180#define inode_in_use(x) (bit(inode_map,(x)))
181#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
182
183#define mark_inode(x) (setbit(inode_map,(x)),changed=1)
184#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1)
185
186#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1)
187#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1)
188
Eric Andersene674eb71999-10-19 20:52:57 +0000189static void leave(int) __attribute__ ((noreturn));
190static void leave(int status)
Eric Andersene494fdd1999-10-19 20:23:03 +0000191{
192 if (termios_set)
193 tcsetattr(0, TCSANOW, &termios);
194 exit(status);
195}
196
Erik Andersene49d5ec2000-02-08 19:58:47 +0000197static void show_usage(void)
198{
199 fprintf(stderr, "BusyBox v%s (%s) multi-call binary -- GPL2\n\n",
200 BB_VER, BB_BT);
Eric Andersend73dc5b1999-11-10 23:13:02 +0000201 fprintf(stderr, "Usage: %s [-larvsmf] /dev/name\n\n", program_name);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000202 fprintf(stderr,
203 "Performs a consistency check for MINIX filesystems.\n\n");
Eric Andersend73dc5b1999-11-10 23:13:02 +0000204 fprintf(stderr, "OPTIONS:\n");
205 fprintf(stderr, "\t-l\tLists all filenames\n");
206 fprintf(stderr, "\t-r\tPerform interactive repairs\n");
207 fprintf(stderr, "\t-a\tPerform automatic repairs\n");
208 fprintf(stderr, "\t-v\tverbose\n");
209 fprintf(stderr, "\t-s\tOutputs super-block information\n");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000210 fprintf(stderr,
211 "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n");
Eric Andersend73dc5b1999-11-10 23:13:02 +0000212 fprintf(stderr, "\t-f\tForce file system check.\n\n");
Eric Andersene494fdd1999-10-19 20:23:03 +0000213 leave(16);
214}
215
Erik Andersene49d5ec2000-02-08 19:58:47 +0000216static void die(const char *str)
217{
Eric Andersene494fdd1999-10-19 20:23:03 +0000218 fprintf(stderr, "%s: %s\n", program_name, str);
219 leave(8);
220}
221
222/*
223 * This simply goes through the file-name data and prints out the
224 * current file.
225 */
Eric Andersene674eb71999-10-19 20:52:57 +0000226static void print_current_name(void)
Eric Andersene494fdd1999-10-19 20:23:03 +0000227{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000228 int i = 0;
Eric Andersene494fdd1999-10-19 20:23:03 +0000229
Erik Andersene49d5ec2000-02-08 19:58:47 +0000230 while (i < name_depth)
231 printf("/%.*s", namelen, name_list[i++]);
Eric Andersene494fdd1999-10-19 20:23:03 +0000232 if (i == 0)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000233 printf("/");
Eric Andersene494fdd1999-10-19 20:23:03 +0000234}
235
Erik Andersene49d5ec2000-02-08 19:58:47 +0000236static int ask(const char *string, int def)
Eric Andersene494fdd1999-10-19 20:23:03 +0000237{
238 int c;
239
240 if (!repair) {
241 printf("\n");
242 errors_uncorrected = 1;
243 return 0;
244 }
245 if (automatic) {
246 printf("\n");
247 if (!def)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000248 errors_uncorrected = 1;
Eric Andersene494fdd1999-10-19 20:23:03 +0000249 return def;
250 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000251 printf(def ? "%s (y/n)? " : "%s (n/y)? ", string);
Eric Andersene494fdd1999-10-19 20:23:03 +0000252 for (;;) {
253 fflush(stdout);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000254 if ((c = getchar()) == EOF) {
255 if (!def)
256 errors_uncorrected = 1;
Eric Andersene494fdd1999-10-19 20:23:03 +0000257 return def;
258 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000259 c = toupper(c);
Eric Andersene494fdd1999-10-19 20:23:03 +0000260 if (c == 'Y') {
261 def = 1;
262 break;
263 } else if (c == 'N') {
264 def = 0;
265 break;
266 } else if (c == ' ' || c == '\n')
267 break;
268 }
269 if (def)
270 printf("y\n");
271 else {
272 printf("n\n");
273 errors_uncorrected = 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000274 }
Eric Andersene494fdd1999-10-19 20:23:03 +0000275 return def;
276}
277
278/*
279 * Make certain that we aren't checking a filesystem that is on a
280 * mounted partition. Code adapted from e2fsck, Copyright (C) 1993,
281 * 1994 Theodore Ts'o. Also licensed under GPL.
282 */
283static void check_mount(void)
284{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000285 FILE *f;
286 struct mntent *mnt;
Eric Andersene494fdd1999-10-19 20:23:03 +0000287 int cont;
288 int fd;
289
Erik Andersene49d5ec2000-02-08 19:58:47 +0000290 if ((f = setmntent(MOUNTED, "r")) == NULL)
Eric Andersene494fdd1999-10-19 20:23:03 +0000291 return;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000292 while ((mnt = getmntent(f)) != NULL)
293 if (strcmp(device_name, mnt->mnt_fsname) == 0)
Eric Andersene494fdd1999-10-19 20:23:03 +0000294 break;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000295 endmntent(f);
Eric Andersene494fdd1999-10-19 20:23:03 +0000296 if (!mnt)
297 return;
298
299 /*
300 * If the root is mounted read-only, then /etc/mtab is
301 * probably not correct; so we won't issue a warning based on
302 * it.
303 */
304 fd = open(MOUNTED, O_RDWR);
305 if (fd < 0 && errno == EROFS)
306 return;
307 else
308 close(fd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000309
310 printf("%s is mounted. ", device_name);
Eric Andersene494fdd1999-10-19 20:23:03 +0000311 if (isatty(0) && isatty(1))
Eric Andersene674eb71999-10-19 20:52:57 +0000312 cont = ask("Do you really want to continue", 0);
Eric Andersene494fdd1999-10-19 20:23:03 +0000313 else
314 cont = 0;
315 if (!cont) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000316 printf("check aborted.\n");
317 exit(0);
Eric Andersene494fdd1999-10-19 20:23:03 +0000318 }
319 return;
320}
321
322/*
323 * check_zone_nr checks to see that *nr is a valid zone nr. If it
324 * isn't, it will possibly be repaired. Check_zone_nr sets *corrected
325 * if an error was corrected, and returns the zone (0 for no zone
326 * or a bad zone-number).
327 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000328static int check_zone_nr(unsigned short *nr, int *corrected)
Eric Andersene494fdd1999-10-19 20:23:03 +0000329{
330 if (!*nr)
331 return 0;
332 if (*nr < FIRSTZONE)
Eric Andersene674eb71999-10-19 20:52:57 +0000333 printf("Zone nr < FIRSTZONE in file `");
Eric Andersene494fdd1999-10-19 20:23:03 +0000334 else if (*nr >= ZONES)
Eric Andersene674eb71999-10-19 20:52:57 +0000335 printf("Zone nr >= ZONES in file `");
Eric Andersene494fdd1999-10-19 20:23:03 +0000336 else
337 return *nr;
338 print_current_name();
339 printf("'.");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000340 if (ask("Remove block", 1)) {
Eric Andersene494fdd1999-10-19 20:23:03 +0000341 *nr = 0;
342 *corrected = 1;
343 }
344 return 0;
345}
346
347#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +0000348static int check_zone_nr2(unsigned int *nr, int *corrected)
Eric Andersene494fdd1999-10-19 20:23:03 +0000349{
350 if (!*nr)
351 return 0;
352 if (*nr < FIRSTZONE)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000353 printf("Zone nr < FIRSTZONE in file `");
Eric Andersene494fdd1999-10-19 20:23:03 +0000354 else if (*nr >= ZONES)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000355 printf("Zone nr >= ZONES in file `");
Eric Andersene494fdd1999-10-19 20:23:03 +0000356 else
357 return *nr;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000358 print_current_name();
359 printf("'.");
360 if (ask("Remove block", 1)) {
Eric Andersene494fdd1999-10-19 20:23:03 +0000361 *nr = 0;
362 *corrected = 1;
363 }
364 return 0;
365}
366#endif
367
368/*
369 * read-block reads block nr into the buffer at addr.
370 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000371static void read_block(unsigned int nr, char *addr)
Eric Andersene494fdd1999-10-19 20:23:03 +0000372{
373 if (!nr) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000374 memset(addr, 0, BLOCK_SIZE);
Eric Andersene494fdd1999-10-19 20:23:03 +0000375 return;
376 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000377 if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) {
Eric Andersene674eb71999-10-19 20:52:57 +0000378 printf("Read error: unable to seek to block in file '");
Eric Andersene494fdd1999-10-19 20:23:03 +0000379 print_current_name();
380 printf("'\n");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000381 memset(addr, 0, BLOCK_SIZE);
Eric Andersene494fdd1999-10-19 20:23:03 +0000382 errors_uncorrected = 1;
383 } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) {
Eric Andersene674eb71999-10-19 20:52:57 +0000384 printf("Read error: bad block in file '");
Eric Andersene494fdd1999-10-19 20:23:03 +0000385 print_current_name();
386 printf("'\n");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000387 memset(addr, 0, BLOCK_SIZE);
Eric Andersene494fdd1999-10-19 20:23:03 +0000388 errors_uncorrected = 1;
389 }
390}
391
392/*
393 * write_block writes block nr to disk.
394 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000395static void write_block(unsigned int nr, char *addr)
Eric Andersene494fdd1999-10-19 20:23:03 +0000396{
397 if (!nr)
398 return;
399 if (nr < FIRSTZONE || nr >= ZONES) {
Eric Andersene674eb71999-10-19 20:52:57 +0000400 printf("Internal error: trying to write bad block\n"
Erik Andersene49d5ec2000-02-08 19:58:47 +0000401 "Write request ignored\n");
Eric Andersene494fdd1999-10-19 20:23:03 +0000402 errors_uncorrected = 1;
403 return;
404 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000405 if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET))
Eric Andersene674eb71999-10-19 20:52:57 +0000406 die("seek failed in write_block");
Eric Andersene494fdd1999-10-19 20:23:03 +0000407 if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) {
Eric Andersene674eb71999-10-19 20:52:57 +0000408 printf("Write error: bad block in file '");
Eric Andersene494fdd1999-10-19 20:23:03 +0000409 print_current_name();
410 printf("'\n");
411 errors_uncorrected = 1;
412 }
413}
414
415/*
416 * map-block calculates the absolute block nr of a block in a file.
417 * It sets 'changed' if the inode has needed changing, and re-writes
418 * any indirect blocks with errors.
419 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000420static int map_block(struct minix_inode *inode, unsigned int blknr)
Eric Andersene494fdd1999-10-19 20:23:03 +0000421{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000422 unsigned short ind[BLOCK_SIZE >> 1];
423 unsigned short dind[BLOCK_SIZE >> 1];
Eric Andersene494fdd1999-10-19 20:23:03 +0000424 int blk_chg, block, result;
425
Erik Andersene49d5ec2000-02-08 19:58:47 +0000426 if (blknr < 7)
Eric Andersene494fdd1999-10-19 20:23:03 +0000427 return check_zone_nr(inode->i_zone + blknr, &changed);
428 blknr -= 7;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000429 if (blknr < 512) {
Eric Andersene494fdd1999-10-19 20:23:03 +0000430 block = check_zone_nr(inode->i_zone + 7, &changed);
431 read_block(block, (char *) ind);
432 blk_chg = 0;
433 result = check_zone_nr(blknr + ind, &blk_chg);
434 if (blk_chg)
435 write_block(block, (char *) ind);
436 return result;
437 }
438 blknr -= 512;
439 block = check_zone_nr(inode->i_zone + 8, &changed);
440 read_block(block, (char *) dind);
441 blk_chg = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000442 result = check_zone_nr(dind + (blknr / 512), &blk_chg);
Eric Andersene494fdd1999-10-19 20:23:03 +0000443 if (blk_chg)
444 write_block(block, (char *) dind);
445 block = result;
446 read_block(block, (char *) ind);
447 blk_chg = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000448 result = check_zone_nr(ind + (blknr % 512), &blk_chg);
Eric Andersene494fdd1999-10-19 20:23:03 +0000449 if (blk_chg)
450 write_block(block, (char *) ind);
451 return result;
452}
453
454#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +0000455static int map_block2(struct minix2_inode *inode, unsigned int blknr)
Eric Andersene494fdd1999-10-19 20:23:03 +0000456{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000457 unsigned int ind[BLOCK_SIZE >> 2];
Eric Andersene494fdd1999-10-19 20:23:03 +0000458 unsigned int dind[BLOCK_SIZE >> 2];
459 unsigned int tind[BLOCK_SIZE >> 2];
460 int blk_chg, block, result;
461
462 if (blknr < 7)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000463 return check_zone_nr2(inode->i_zone + blknr, &changed);
Eric Andersene494fdd1999-10-19 20:23:03 +0000464 blknr -= 7;
465 if (blknr < 256) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000466 block = check_zone_nr2(inode->i_zone + 7, &changed);
467 read_block(block, (char *) ind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000468 blk_chg = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000469 result = check_zone_nr2(blknr + ind, &blk_chg);
Eric Andersene494fdd1999-10-19 20:23:03 +0000470 if (blk_chg)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000471 write_block(block, (char *) ind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000472 return result;
473 }
474 blknr -= 256;
475 if (blknr >= 256 * 256) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000476 block = check_zone_nr2(inode->i_zone + 8, &changed);
477 read_block(block, (char *) dind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000478 blk_chg = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000479 result = check_zone_nr2(dind + blknr / 256, &blk_chg);
Eric Andersene494fdd1999-10-19 20:23:03 +0000480 if (blk_chg)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000481 write_block(block, (char *) dind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000482 block = result;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000483 read_block(block, (char *) ind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000484 blk_chg = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000485 result = check_zone_nr2(ind + blknr % 256, &blk_chg);
Eric Andersene494fdd1999-10-19 20:23:03 +0000486 if (blk_chg)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000487 write_block(block, (char *) ind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000488 return result;
489 }
490 blknr -= 256 * 256;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000491 block = check_zone_nr2(inode->i_zone + 9, &changed);
492 read_block(block, (char *) tind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000493 blk_chg = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000494 result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg);
Eric Andersene494fdd1999-10-19 20:23:03 +0000495 if (blk_chg)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000496 write_block(block, (char *) tind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000497 block = result;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000498 read_block(block, (char *) dind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000499 blk_chg = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000500 result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg);
Eric Andersene494fdd1999-10-19 20:23:03 +0000501 if (blk_chg)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000502 write_block(block, (char *) dind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000503 block = result;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000504 read_block(block, (char *) ind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000505 blk_chg = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000506 result = check_zone_nr2(ind + blknr % 256, &blk_chg);
Eric Andersene494fdd1999-10-19 20:23:03 +0000507 if (blk_chg)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000508 write_block(block, (char *) ind);
Eric Andersene494fdd1999-10-19 20:23:03 +0000509 return result;
510}
511#endif
512
Eric Andersene674eb71999-10-19 20:52:57 +0000513static void write_super_block(void)
Eric Andersene494fdd1999-10-19 20:23:03 +0000514{
515 /*
516 * Set the state of the filesystem based on whether or not there
517 * are uncorrected errors. The filesystem valid flag is
518 * unconditionally set if we get this far.
519 */
520 Super.s_state |= MINIX_VALID_FS;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000521 if (errors_uncorrected)
Eric Andersene494fdd1999-10-19 20:23:03 +0000522 Super.s_state |= MINIX_ERROR_FS;
523 else
524 Super.s_state &= ~MINIX_ERROR_FS;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000525
Eric Andersene494fdd1999-10-19 20:23:03 +0000526 if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
Eric Andersene674eb71999-10-19 20:52:57 +0000527 die("seek failed in write_super_block");
Eric Andersene494fdd1999-10-19 20:23:03 +0000528 if (BLOCK_SIZE != write(IN, super_block_buffer, BLOCK_SIZE))
Eric Andersene674eb71999-10-19 20:52:57 +0000529 die("unable to write super-block");
Eric Andersene494fdd1999-10-19 20:23:03 +0000530
531 return;
532}
533
Eric Andersene674eb71999-10-19 20:52:57 +0000534static void write_tables(void)
Eric Andersene494fdd1999-10-19 20:23:03 +0000535{
536 write_super_block();
537
Erik Andersene49d5ec2000-02-08 19:58:47 +0000538 if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE))
Eric Andersene674eb71999-10-19 20:52:57 +0000539 die("Unable to write inode map");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000540 if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE))
Eric Andersene674eb71999-10-19 20:52:57 +0000541 die("Unable to write zone map");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000542 if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE))
Eric Andersene674eb71999-10-19 20:52:57 +0000543 die("Unable to write inodes");
Eric Andersene494fdd1999-10-19 20:23:03 +0000544}
545
Erik Andersene49d5ec2000-02-08 19:58:47 +0000546static void get_dirsize(void)
Eric Andersene494fdd1999-10-19 20:23:03 +0000547{
548 int block;
549 char blk[BLOCK_SIZE];
550 int size;
551
552#if HAVE_MINIX2
553 if (version2)
554 block = Inode2[ROOT_INO].i_zone[0];
555 else
556#endif
557 block = Inode[ROOT_INO].i_zone[0];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000558 read_block(block, blk);
Eric Andersene494fdd1999-10-19 20:23:03 +0000559 for (size = 16; size < BLOCK_SIZE; size <<= 1) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000560 if (strcmp(blk + size + 2, "..") == 0) {
Eric Andersene494fdd1999-10-19 20:23:03 +0000561 dirsize = size;
562 namelen = size - 2;
563 return;
564 }
565 }
566 /* use defaults */
567}
568
Eric Andersene674eb71999-10-19 20:52:57 +0000569static void read_superblock(void)
Eric Andersene494fdd1999-10-19 20:23:03 +0000570{
571 if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
Eric Andersene674eb71999-10-19 20:52:57 +0000572 die("seek failed");
Eric Andersene494fdd1999-10-19 20:23:03 +0000573 if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE))
Eric Andersene674eb71999-10-19 20:52:57 +0000574 die("unable to read super block");
Eric Andersene494fdd1999-10-19 20:23:03 +0000575 if (MAGIC == MINIX_SUPER_MAGIC) {
576 namelen = 14;
577 dirsize = 16;
578 version2 = 0;
579 } else if (MAGIC == MINIX_SUPER_MAGIC2) {
580 namelen = 30;
581 dirsize = 32;
582 version2 = 0;
583#ifdef HAVE_MINIX2
584 } else if (MAGIC == MINIX2_SUPER_MAGIC) {
585 namelen = 14;
586 dirsize = 16;
587 version2 = 1;
588 } else if (MAGIC == MINIX2_SUPER_MAGIC2) {
589 namelen = 30;
590 dirsize = 32;
591 version2 = 1;
592#endif
593 } else
Eric Andersene674eb71999-10-19 20:52:57 +0000594 die("bad magic number in super-block");
Eric Andersene494fdd1999-10-19 20:23:03 +0000595 if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
Eric Andersene674eb71999-10-19 20:52:57 +0000596 die("Only 1k blocks/zones supported");
Eric Andersene494fdd1999-10-19 20:23:03 +0000597 if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
Eric Andersene674eb71999-10-19 20:52:57 +0000598 die("bad s_imap_blocks field in super-block");
Eric Andersene494fdd1999-10-19 20:23:03 +0000599 if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
Eric Andersene674eb71999-10-19 20:52:57 +0000600 die("bad s_zmap_blocks field in super-block");
Eric Andersene494fdd1999-10-19 20:23:03 +0000601}
602
Eric Andersene674eb71999-10-19 20:52:57 +0000603static void read_tables(void)
Eric Andersene494fdd1999-10-19 20:23:03 +0000604{
605 inode_map = malloc(IMAPS * BLOCK_SIZE);
606 if (!inode_map)
Eric Andersene674eb71999-10-19 20:52:57 +0000607 die("Unable to allocate buffer for inode map");
Eric Andersene494fdd1999-10-19 20:23:03 +0000608 zone_map = malloc(ZMAPS * BLOCK_SIZE);
609 if (!inode_map)
610 die("Unable to allocate buffer for zone map");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000611 memset(inode_map, 0, sizeof(inode_map));
612 memset(zone_map, 0, sizeof(zone_map));
Eric Andersene494fdd1999-10-19 20:23:03 +0000613 inode_buffer = malloc(INODE_BUFFER_SIZE);
614 if (!inode_buffer)
Eric Andersene674eb71999-10-19 20:52:57 +0000615 die("Unable to allocate buffer for inodes");
Eric Andersene494fdd1999-10-19 20:23:03 +0000616 inode_count = malloc(INODES + 1);
617 if (!inode_count)
Eric Andersene674eb71999-10-19 20:52:57 +0000618 die("Unable to allocate buffer for inode count");
Eric Andersene494fdd1999-10-19 20:23:03 +0000619 zone_count = malloc(ZONES);
620 if (!zone_count)
Eric Andersene674eb71999-10-19 20:52:57 +0000621 die("Unable to allocate buffer for zone count");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000622 if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE))
Eric Andersene674eb71999-10-19 20:52:57 +0000623 die("Unable to read inode map");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000624 if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE))
Eric Andersene674eb71999-10-19 20:52:57 +0000625 die("Unable to read zone map");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000626 if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE))
Eric Andersene674eb71999-10-19 20:52:57 +0000627 die("Unable to read inodes");
Eric Andersene494fdd1999-10-19 20:23:03 +0000628 if (NORM_FIRSTZONE != FIRSTZONE) {
Eric Andersene674eb71999-10-19 20:52:57 +0000629 printf("Warning: Firstzone != Norm_firstzone\n");
Eric Andersene494fdd1999-10-19 20:23:03 +0000630 errors_uncorrected = 1;
631 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000632 get_dirsize();
Eric Andersene494fdd1999-10-19 20:23:03 +0000633 if (show) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000634 printf("%ld inodes\n", INODES);
635 printf("%ld blocks\n", ZONES);
636 printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE);
637 printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE);
638 printf("Maxsize=%ld\n", MAXSIZE);
Eric Andersene674eb71999-10-19 20:52:57 +0000639 printf("Filesystem state=%d\n", Super.s_state);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000640 printf("namelen=%d\n\n", namelen);
Eric Andersene494fdd1999-10-19 20:23:03 +0000641 }
642}
643
Erik Andersene49d5ec2000-02-08 19:58:47 +0000644struct minix_inode *get_inode(unsigned int nr)
Eric Andersene494fdd1999-10-19 20:23:03 +0000645{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000646 struct minix_inode *inode;
Eric Andersene494fdd1999-10-19 20:23:03 +0000647
648 if (!nr || nr > INODES)
649 return NULL;
650 total++;
651 inode = Inode + nr;
652 if (!inode_count[nr]) {
653 if (!inode_in_use(nr)) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000654 printf("Inode %d marked not used, but used for file '", nr);
Eric Andersene494fdd1999-10-19 20:23:03 +0000655 print_current_name();
656 printf("'\n");
657 if (repair) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000658 if (ask("Mark in use", 1))
Eric Andersene494fdd1999-10-19 20:23:03 +0000659 mark_inode(nr);
660 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000661 errors_uncorrected = 1;
Eric Andersene494fdd1999-10-19 20:23:03 +0000662 }
663 }
664 if (S_ISDIR(inode->i_mode))
665 directory++;
666 else if (S_ISREG(inode->i_mode))
667 regular++;
668 else if (S_ISCHR(inode->i_mode))
669 chardev++;
670 else if (S_ISBLK(inode->i_mode))
671 blockdev++;
672 else if (S_ISLNK(inode->i_mode))
673 symlinks++;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000674 else if (S_ISSOCK(inode->i_mode));
675 else if (S_ISFIFO(inode->i_mode));
Eric Andersene494fdd1999-10-19 20:23:03 +0000676 else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000677 print_current_name();
678 printf(" has mode %05o\n", inode->i_mode);
679 }
Eric Andersene494fdd1999-10-19 20:23:03 +0000680
681 } else
682 links++;
683 if (!++inode_count[nr]) {
Eric Andersene674eb71999-10-19 20:52:57 +0000684 printf("Warning: inode count too big.\n");
Eric Andersene494fdd1999-10-19 20:23:03 +0000685 inode_count[nr]--;
686 errors_uncorrected = 1;
687 }
688 return inode;
689}
690
691#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +0000692struct minix2_inode *get_inode2(unsigned int nr)
Eric Andersene494fdd1999-10-19 20:23:03 +0000693{
694 struct minix2_inode *inode;
695
696 if (!nr || nr > INODES)
697 return NULL;
698 total++;
699 inode = Inode2 + nr;
700 if (!inode_count[nr]) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000701 if (!inode_in_use(nr)) {
702 printf("Inode %d marked not used, but used for file '", nr);
703 print_current_name();
704 printf("'\n");
Eric Andersene494fdd1999-10-19 20:23:03 +0000705 if (repair) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000706 if (ask("Mark in use", 1))
707 mark_inode(nr);
Eric Andersene494fdd1999-10-19 20:23:03 +0000708 else
709 errors_uncorrected = 1;
710 }
711 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000712 if (S_ISDIR(inode->i_mode))
Eric Andersene494fdd1999-10-19 20:23:03 +0000713 directory++;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000714 else if (S_ISREG(inode->i_mode))
Eric Andersene494fdd1999-10-19 20:23:03 +0000715 regular++;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000716 else if (S_ISCHR(inode->i_mode))
Eric Andersene494fdd1999-10-19 20:23:03 +0000717 chardev++;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000718 else if (S_ISBLK(inode->i_mode))
Eric Andersene494fdd1999-10-19 20:23:03 +0000719 blockdev++;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000720 else if (S_ISLNK(inode->i_mode))
Eric Andersene494fdd1999-10-19 20:23:03 +0000721 symlinks++;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000722 else if (S_ISSOCK(inode->i_mode));
723 else if (S_ISFIFO(inode->i_mode));
Eric Andersene494fdd1999-10-19 20:23:03 +0000724 else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000725 print_current_name();
726 printf(" has mode %05o\n", inode->i_mode);
Eric Andersene494fdd1999-10-19 20:23:03 +0000727 }
728 } else
729 links++;
730 if (!++inode_count[nr]) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000731 printf("Warning: inode count too big.\n");
Eric Andersene494fdd1999-10-19 20:23:03 +0000732 inode_count[nr]--;
733 errors_uncorrected = 1;
734 }
735 return inode;
736}
737#endif
738
Eric Andersene674eb71999-10-19 20:52:57 +0000739static void check_root(void)
Eric Andersene494fdd1999-10-19 20:23:03 +0000740{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000741 struct minix_inode *inode = Inode + ROOT_INO;
Eric Andersene494fdd1999-10-19 20:23:03 +0000742
743 if (!inode || !S_ISDIR(inode->i_mode))
Eric Andersene674eb71999-10-19 20:52:57 +0000744 die("root inode isn't a directory");
Eric Andersene494fdd1999-10-19 20:23:03 +0000745}
746
747#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +0000748static void check_root2(void)
Eric Andersene494fdd1999-10-19 20:23:03 +0000749{
750 struct minix2_inode *inode = Inode2 + ROOT_INO;
751
Erik Andersene49d5ec2000-02-08 19:58:47 +0000752 if (!inode || !S_ISDIR(inode->i_mode))
753 die("root inode isn't a directory");
Eric Andersene494fdd1999-10-19 20:23:03 +0000754}
755#endif
756
Erik Andersene49d5ec2000-02-08 19:58:47 +0000757static int add_zone(unsigned short *znr, int *corrected)
Eric Andersene494fdd1999-10-19 20:23:03 +0000758{
759 int result;
760 int block;
761
762 result = 0;
763 block = check_zone_nr(znr, corrected);
764 if (!block)
765 return 0;
766 if (zone_count[block]) {
Eric Andersene674eb71999-10-19 20:52:57 +0000767 printf("Block has been used before. Now in file `");
Eric Andersene494fdd1999-10-19 20:23:03 +0000768 print_current_name();
769 printf("'.");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000770 if (ask("Clear", 1)) {
Eric Andersene494fdd1999-10-19 20:23:03 +0000771 *znr = 0;
772 block = 0;
773 *corrected = 1;
774 }
775 }
776 if (!block)
777 return 0;
778 if (!zone_in_use(block)) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000779 printf("Block %d in file `", block);
Eric Andersene494fdd1999-10-19 20:23:03 +0000780 print_current_name();
Eric Andersene674eb71999-10-19 20:52:57 +0000781 printf("' is marked not in use.");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000782 if (ask("Correct", 1))
Eric Andersene494fdd1999-10-19 20:23:03 +0000783 mark_zone(block);
784 }
785 if (!++zone_count[block])
786 zone_count[block]--;
787 return block;
788}
789
790#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +0000791static int add_zone2(unsigned int *znr, int *corrected)
Eric Andersene494fdd1999-10-19 20:23:03 +0000792{
793 int result;
794 int block;
795
796 result = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000797 block = check_zone_nr2(znr, corrected);
Eric Andersene494fdd1999-10-19 20:23:03 +0000798 if (!block)
799 return 0;
800 if (zone_count[block]) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000801 printf("Block has been used before. Now in file `");
802 print_current_name();
803 printf("'.");
804 if (ask("Clear", 1)) {
Eric Andersene494fdd1999-10-19 20:23:03 +0000805 *znr = 0;
806 block = 0;
807 *corrected = 1;
808 }
809 }
810 if (!block)
811 return 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000812 if (!zone_in_use(block)) {
813 printf("Block %d in file `", block);
814 print_current_name();
815 printf("' is marked not in use.");
816 if (ask("Correct", 1))
817 mark_zone(block);
Eric Andersene494fdd1999-10-19 20:23:03 +0000818 }
819 if (!++zone_count[block])
820 zone_count[block]--;
821 return block;
822}
823#endif
824
Erik Andersene49d5ec2000-02-08 19:58:47 +0000825static void add_zone_ind(unsigned short *znr, int *corrected)
Eric Andersene494fdd1999-10-19 20:23:03 +0000826{
827 static char blk[BLOCK_SIZE];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000828 int i, chg_blk = 0;
Eric Andersene494fdd1999-10-19 20:23:03 +0000829 int block;
830
831 block = add_zone(znr, corrected);
832 if (!block)
833 return;
834 read_block(block, blk);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000835 for (i = 0; i < (BLOCK_SIZE >> 1); i++)
Eric Andersene494fdd1999-10-19 20:23:03 +0000836 add_zone(i + (unsigned short *) blk, &chg_blk);
837 if (chg_blk)
838 write_block(block, blk);
839}
840
841#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +0000842static void add_zone_ind2(unsigned int *znr, int *corrected)
Eric Andersene494fdd1999-10-19 20:23:03 +0000843{
844 static char blk[BLOCK_SIZE];
845 int i, chg_blk = 0;
846 int block;
847
Erik Andersene49d5ec2000-02-08 19:58:47 +0000848 block = add_zone2(znr, corrected);
Eric Andersene494fdd1999-10-19 20:23:03 +0000849 if (!block)
850 return;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000851 read_block(block, blk);
Eric Andersene494fdd1999-10-19 20:23:03 +0000852 for (i = 0; i < BLOCK_SIZE >> 2; i++)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000853 add_zone2(i + (unsigned int *) blk, &chg_blk);
Eric Andersene494fdd1999-10-19 20:23:03 +0000854 if (chg_blk)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000855 write_block(block, blk);
Eric Andersene494fdd1999-10-19 20:23:03 +0000856}
857#endif
858
Erik Andersene49d5ec2000-02-08 19:58:47 +0000859static void add_zone_dind(unsigned short *znr, int *corrected)
Eric Andersene494fdd1999-10-19 20:23:03 +0000860{
861 static char blk[BLOCK_SIZE];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000862 int i, blk_chg = 0;
Eric Andersene494fdd1999-10-19 20:23:03 +0000863 int block;
864
865 block = add_zone(znr, corrected);
866 if (!block)
867 return;
868 read_block(block, blk);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000869 for (i = 0; i < (BLOCK_SIZE >> 1); i++)
Eric Andersene494fdd1999-10-19 20:23:03 +0000870 add_zone_ind(i + (unsigned short *) blk, &blk_chg);
871 if (blk_chg)
872 write_block(block, blk);
873}
874
875#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +0000876static void add_zone_dind2(unsigned int *znr, int *corrected)
Eric Andersene494fdd1999-10-19 20:23:03 +0000877{
878 static char blk[BLOCK_SIZE];
879 int i, blk_chg = 0;
880 int block;
881
Erik Andersene49d5ec2000-02-08 19:58:47 +0000882 block = add_zone2(znr, corrected);
Eric Andersene494fdd1999-10-19 20:23:03 +0000883 if (!block)
884 return;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000885 read_block(block, blk);
Eric Andersene494fdd1999-10-19 20:23:03 +0000886 for (i = 0; i < BLOCK_SIZE >> 2; i++)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000887 add_zone_ind2(i + (unsigned int *) blk, &blk_chg);
Eric Andersene494fdd1999-10-19 20:23:03 +0000888 if (blk_chg)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000889 write_block(block, blk);
Eric Andersene494fdd1999-10-19 20:23:03 +0000890}
891
Erik Andersene49d5ec2000-02-08 19:58:47 +0000892static void add_zone_tind2(unsigned int *znr, int *corrected)
Eric Andersene494fdd1999-10-19 20:23:03 +0000893{
894 static char blk[BLOCK_SIZE];
895 int i, blk_chg = 0;
896 int block;
897
Erik Andersene49d5ec2000-02-08 19:58:47 +0000898 block = add_zone2(znr, corrected);
Eric Andersene494fdd1999-10-19 20:23:03 +0000899 if (!block)
900 return;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000901 read_block(block, blk);
Eric Andersene494fdd1999-10-19 20:23:03 +0000902 for (i = 0; i < BLOCK_SIZE >> 2; i++)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000903 add_zone_dind2(i + (unsigned int *) blk, &blk_chg);
Eric Andersene494fdd1999-10-19 20:23:03 +0000904 if (blk_chg)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000905 write_block(block, blk);
Eric Andersene494fdd1999-10-19 20:23:03 +0000906}
907#endif
908
Eric Andersene674eb71999-10-19 20:52:57 +0000909static void check_zones(unsigned int i)
Eric Andersene494fdd1999-10-19 20:23:03 +0000910{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000911 struct minix_inode *inode;
Eric Andersene494fdd1999-10-19 20:23:03 +0000912
913 if (!i || i > INODES)
914 return;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000915 if (inode_count[i] > 1) /* have we counted this file already? */
Eric Andersene494fdd1999-10-19 20:23:03 +0000916 return;
917 inode = Inode + i;
918 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
Erik Andersene49d5ec2000-02-08 19:58:47 +0000919 !S_ISLNK(inode->i_mode)) return;
920 for (i = 0; i < 7; i++)
Eric Andersene494fdd1999-10-19 20:23:03 +0000921 add_zone(i + inode->i_zone, &changed);
922 add_zone_ind(7 + inode->i_zone, &changed);
923 add_zone_dind(8 + inode->i_zone, &changed);
924}
925
926#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +0000927static void check_zones2(unsigned int i)
Eric Andersene494fdd1999-10-19 20:23:03 +0000928{
929 struct minix2_inode *inode;
930
931 if (!i || i > INODES)
932 return;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000933 if (inode_count[i] > 1) /* have we counted this file already? */
Eric Andersene494fdd1999-10-19 20:23:03 +0000934 return;
935 inode = Inode2 + i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000936 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode)
937 && !S_ISLNK(inode->i_mode))
Eric Andersene494fdd1999-10-19 20:23:03 +0000938 return;
939 for (i = 0; i < 7; i++)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000940 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);
Eric Andersene494fdd1999-10-19 20:23:03 +0000944}
945#endif
946
Erik Andersene49d5ec2000-02-08 19:58:47 +0000947static void check_file(struct minix_inode *dir, unsigned int offset)
Eric Andersene494fdd1999-10-19 20:23:03 +0000948{
949 static char blk[BLOCK_SIZE];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000950 struct minix_inode *inode;
Eric Andersene494fdd1999-10-19 20:23:03 +0000951 int ino;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000952 char *name;
Eric Andersene494fdd1999-10-19 20:23:03 +0000953 int block;
954
Erik Andersene49d5ec2000-02-08 19:58:47 +0000955 block = map_block(dir, offset / BLOCK_SIZE);
Eric Andersene494fdd1999-10-19 20:23:03 +0000956 read_block(block, blk);
957 name = blk + (offset % BLOCK_SIZE) + 2;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000958 ino = *(unsigned short *) (name - 2);
Eric Andersene494fdd1999-10-19 20:23:03 +0000959 if (ino > INODES) {
960 print_current_name();
Eric Andersene674eb71999-10-19 20:52:57 +0000961 printf(" contains a bad inode number for file '");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000962 printf("%.*s'.", namelen, name);
963 if (ask(" Remove", 1)) {
964 *(unsigned short *) (name - 2) = 0;
Eric Andersene494fdd1999-10-19 20:23:03 +0000965 write_block(block, blk);
966 }
967 ino = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000968 }
Eric Andersene494fdd1999-10-19 20:23:03 +0000969 if (name_depth < MAX_DEPTH)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000970 strncpy(name_list[name_depth], name, namelen);
Eric Andersene494fdd1999-10-19 20:23:03 +0000971 name_depth++;
972 inode = get_inode(ino);
973 name_depth--;
974 if (!offset) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000975 if (!inode || strcmp(".", name)) {
Eric Andersene494fdd1999-10-19 20:23:03 +0000976 print_current_name();
Eric Andersene674eb71999-10-19 20:52:57 +0000977 printf(": bad directory: '.' isn't first\n");
Eric Andersene494fdd1999-10-19 20:23:03 +0000978 errors_uncorrected = 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000979 } else
980 return;
Eric Andersene494fdd1999-10-19 20:23:03 +0000981 }
982 if (offset == dirsize) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000983 if (!inode || strcmp("..", name)) {
Eric Andersene494fdd1999-10-19 20:23:03 +0000984 print_current_name();
Eric Andersene674eb71999-10-19 20:52:57 +0000985 printf(": bad directory: '..' isn't second\n");
Eric Andersene494fdd1999-10-19 20:23:03 +0000986 errors_uncorrected = 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000987 } else
988 return;
Eric Andersene494fdd1999-10-19 20:23:03 +0000989 }
990 if (!inode)
991 return;
992 if (name_depth < MAX_DEPTH)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000993 strncpy(name_list[name_depth], name, namelen);
994 name_depth++;
Eric Andersene494fdd1999-10-19 20:23:03 +0000995 if (list) {
996 if (verbose)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000997 printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
Eric Andersene494fdd1999-10-19 20:23:03 +0000998 print_current_name();
999 if (S_ISDIR(inode->i_mode))
1000 printf(":\n");
1001 else
1002 printf("\n");
1003 }
1004 check_zones(ino);
1005 if (inode && S_ISDIR(inode->i_mode))
1006 recursive_check(ino);
1007 name_depth--;
1008 return;
1009}
1010
1011#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +00001012static void check_file2(struct minix2_inode *dir, unsigned int offset)
Eric Andersene494fdd1999-10-19 20:23:03 +00001013{
1014 static char blk[BLOCK_SIZE];
1015 struct minix2_inode *inode;
1016 int ino;
1017 char *name;
1018 int block;
1019
Erik Andersene49d5ec2000-02-08 19:58:47 +00001020 block = map_block2(dir, offset / BLOCK_SIZE);
1021 read_block(block, blk);
Eric Andersene494fdd1999-10-19 20:23:03 +00001022 name = blk + (offset % BLOCK_SIZE) + 2;
1023 ino = *(unsigned short *) (name - 2);
1024 if (ino > INODES) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001025 print_current_name();
1026 printf(" contains a bad inode number for file '");
1027 printf("%.*s'.", namelen, name);
1028 if (ask(" Remove", 1)) {
Eric Andersene494fdd1999-10-19 20:23:03 +00001029 *(unsigned short *) (name - 2) = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001030 write_block(block, blk);
Eric Andersene494fdd1999-10-19 20:23:03 +00001031 }
1032 ino = 0;
1033 }
1034 if (name_depth < MAX_DEPTH)
Erik Andersene49d5ec2000-02-08 19:58:47 +00001035 strncpy(name_list[name_depth], name, namelen);
Eric Andersene494fdd1999-10-19 20:23:03 +00001036 name_depth++;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001037 inode = get_inode2(ino);
Eric Andersene494fdd1999-10-19 20:23:03 +00001038 name_depth--;
1039 if (!offset) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001040 if (!inode || strcmp(".", name)) {
1041 print_current_name();
1042 printf(": bad directory: '.' isn't first\n");
Eric Andersene494fdd1999-10-19 20:23:03 +00001043 errors_uncorrected = 1;
1044 } else
1045 return;
1046 }
1047 if (offset == dirsize) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001048 if (!inode || strcmp("..", name)) {
1049 print_current_name();
1050 printf(": bad directory: '..' isn't second\n");
Eric Andersene494fdd1999-10-19 20:23:03 +00001051 errors_uncorrected = 1;
1052 } else
1053 return;
1054 }
1055 if (!inode)
1056 return;
1057 name_depth++;
1058 if (list) {
1059 if (verbose)
Erik Andersene49d5ec2000-02-08 19:58:47 +00001060 printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
1061 print_current_name();
1062 if (S_ISDIR(inode->i_mode))
1063 printf(":\n");
Eric Andersene494fdd1999-10-19 20:23:03 +00001064 else
Erik Andersene49d5ec2000-02-08 19:58:47 +00001065 printf("\n");
Eric Andersene494fdd1999-10-19 20:23:03 +00001066 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001067 check_zones2(ino);
1068 if (inode && S_ISDIR(inode->i_mode))
1069 recursive_check2(ino);
Eric Andersene494fdd1999-10-19 20:23:03 +00001070 name_depth--;
1071 return;
1072}
1073#endif
1074
Eric Andersene674eb71999-10-19 20:52:57 +00001075static void recursive_check(unsigned int ino)
Eric Andersene494fdd1999-10-19 20:23:03 +00001076{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001077 struct minix_inode *dir;
Eric Andersene494fdd1999-10-19 20:23:03 +00001078 unsigned int offset;
1079
1080 dir = Inode + ino;
1081 if (!S_ISDIR(dir->i_mode))
Eric Andersene674eb71999-10-19 20:52:57 +00001082 die("internal error");
Eric Andersene494fdd1999-10-19 20:23:03 +00001083 if (dir->i_size < 2 * dirsize) {
1084 print_current_name();
Eric Andersene674eb71999-10-19 20:52:57 +00001085 printf(": bad directory: size<32");
Eric Andersene494fdd1999-10-19 20:23:03 +00001086 errors_uncorrected = 1;
1087 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001088 for (offset = 0; offset < dir->i_size; offset += dirsize)
1089 check_file(dir, offset);
Eric Andersene494fdd1999-10-19 20:23:03 +00001090}
1091
1092#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +00001093static void recursive_check2(unsigned int ino)
Eric Andersene494fdd1999-10-19 20:23:03 +00001094{
1095 struct minix2_inode *dir;
1096 unsigned int offset;
1097
1098 dir = Inode2 + ino;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001099 if (!S_ISDIR(dir->i_mode))
1100 die("internal error");
Eric Andersene494fdd1999-10-19 20:23:03 +00001101 if (dir->i_size < 2 * dirsize) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001102 print_current_name();
1103 printf(": bad directory: size < 32");
Eric Andersene494fdd1999-10-19 20:23:03 +00001104 errors_uncorrected = 1;
1105 }
1106 for (offset = 0; offset < dir->i_size; offset += dirsize)
Erik Andersene49d5ec2000-02-08 19:58:47 +00001107 check_file2(dir, offset);
Eric Andersene494fdd1999-10-19 20:23:03 +00001108}
1109#endif
1110
Eric Andersene674eb71999-10-19 20:52:57 +00001111static int bad_zone(int i)
Eric Andersene494fdd1999-10-19 20:23:03 +00001112{
1113 char buffer[1024];
1114
Erik Andersene49d5ec2000-02-08 19:58:47 +00001115 if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET))
Eric Andersene674eb71999-10-19 20:52:57 +00001116 die("seek failed in bad_zone");
Eric Andersene494fdd1999-10-19 20:23:03 +00001117 return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE));
1118}
1119
Eric Andersene674eb71999-10-19 20:52:57 +00001120static void check_counts(void)
Eric Andersene494fdd1999-10-19 20:23:03 +00001121{
1122 int i;
1123
Erik Andersene49d5ec2000-02-08 19:58:47 +00001124 for (i = 1; i <= INODES; i++) {
Eric Andersene494fdd1999-10-19 20:23:03 +00001125 if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001126 printf("Inode %d mode not cleared.", i);
1127 if (ask("Clear", 1)) {
Eric Andersene494fdd1999-10-19 20:23:03 +00001128 Inode[i].i_mode = 0;
1129 changed = 1;
1130 }
1131 }
1132 if (!inode_count[i]) {
1133 if (!inode_in_use(i))
1134 continue;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001135 printf("Inode %d not used, marked used in the bitmap.", i);
1136 if (ask("Clear", 1))
Eric Andersene494fdd1999-10-19 20:23:03 +00001137 unmark_inode(i);
1138 continue;
1139 }
1140 if (!inode_in_use(i)) {
Eric Andersene674eb71999-10-19 20:52:57 +00001141 printf("Inode %d used, marked unused in the bitmap.", i);
Erik Andersene49d5ec2000-02-08 19:58:47 +00001142 if (ask("Set", 1))
Eric Andersene494fdd1999-10-19 20:23:03 +00001143 mark_inode(i);
1144 }
1145 if (Inode[i].i_nlinks != inode_count[i]) {
Eric Andersene674eb71999-10-19 20:52:57 +00001146 printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.",
Erik Andersene49d5ec2000-02-08 19:58:47 +00001147 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;
Eric Andersene494fdd1999-10-19 20:23:03 +00001151 }
1152 }
1153 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001154 for (i = FIRSTZONE; i < ZONES; i++) {
Eric Andersene494fdd1999-10-19 20:23:03 +00001155 if (zone_in_use(i) == zone_count[i])
1156 continue;
1157 if (!zone_count[i]) {
1158 if (bad_zone(i))
1159 continue;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001160 printf("Zone %d: marked in use, no file uses it.", i);
1161 if (ask("Unmark", 1))
Eric Andersene494fdd1999-10-19 20:23:03 +00001162 unmark_zone(i);
1163 continue;
1164 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001165 printf("Zone %d: %sin use, counted=%d\n",
1166 i, zone_in_use(i) ? "" : "not ", zone_count[i]);
Eric Andersene494fdd1999-10-19 20:23:03 +00001167 }
1168}
1169
1170#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +00001171static void check_counts2(void)
Eric Andersene494fdd1999-10-19 20:23:03 +00001172{
1173 int i;
1174
1175 for (i = 1; i <= INODES; i++) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001176 if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) {
1177 printf("Inode %d mode not cleared.", i);
1178 if (ask("Clear", 1)) {
Eric Andersene494fdd1999-10-19 20:23:03 +00001179 Inode2[i].i_mode = 0;
1180 changed = 1;
1181 }
1182 }
1183 if (!inode_count[i]) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001184 if (!inode_in_use(i))
Eric Andersene494fdd1999-10-19 20:23:03 +00001185 continue;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001186 printf("Inode %d not used, marked used in the bitmap.", i);
1187 if (ask("Clear", 1))
1188 unmark_inode(i);
Eric Andersene494fdd1999-10-19 20:23:03 +00001189 continue;
1190 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001191 if (!inode_in_use(i)) {
1192 printf("Inode %d used, marked unused in the bitmap.", i);
1193 if (ask("Set", 1))
1194 mark_inode(i);
Eric Andersene494fdd1999-10-19 20:23:03 +00001195 }
1196 if (Inode2[i].i_nlinks != inode_count[i]) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001197 printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.",
1198 i, Inode2[i].i_mode, Inode2[i].i_nlinks,
1199 inode_count[i]);
1200 if (ask("Set i_nlinks to count", 1)) {
Eric Andersene494fdd1999-10-19 20:23:03 +00001201 Inode2[i].i_nlinks = inode_count[i];
1202 changed = 1;
1203 }
1204 }
1205 }
1206 for (i = FIRSTZONE; i < ZONES; i++) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001207 if (zone_in_use(i) == zone_count[i])
Eric Andersene494fdd1999-10-19 20:23:03 +00001208 continue;
1209 if (!zone_count[i]) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001210 if (bad_zone(i))
Eric Andersene494fdd1999-10-19 20:23:03 +00001211 continue;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001212 printf("Zone %d: marked in use, no file uses it.", i);
1213 if (ask("Unmark", 1))
1214 unmark_zone(i);
Eric Andersene494fdd1999-10-19 20:23:03 +00001215 continue;
1216 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001217 printf("Zone %d: %sin use, counted=%d\n",
1218 i, zone_in_use(i) ? "" : "not ", zone_count[i]);
Eric Andersene494fdd1999-10-19 20:23:03 +00001219 }
1220}
1221#endif
1222
Eric Andersene674eb71999-10-19 20:52:57 +00001223static void check(void)
Eric Andersene494fdd1999-10-19 20:23:03 +00001224{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001225 memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
1226 memset(zone_count, 0, ZONES * sizeof(*zone_count));
Eric Andersene494fdd1999-10-19 20:23:03 +00001227 check_zones(ROOT_INO);
1228 recursive_check(ROOT_INO);
1229 check_counts();
1230}
1231
1232#ifdef HAVE_MINIX2
Erik Andersene49d5ec2000-02-08 19:58:47 +00001233static void check2(void)
Eric Andersene494fdd1999-10-19 20:23:03 +00001234{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001235 memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
1236 memset(zone_count, 0, ZONES * sizeof(*zone_count));
1237 check_zones2(ROOT_INO);
1238 recursive_check2(ROOT_INO);
1239 check_counts2();
Eric Andersene494fdd1999-10-19 20:23:03 +00001240}
1241#endif
1242
Erik Andersene49d5ec2000-02-08 19:58:47 +00001243extern int fsck_minix_main(int argc, char **argv)
Eric Andersene494fdd1999-10-19 20:23:03 +00001244{
1245 struct termios tmp;
1246 int count;
1247 int retcode = 0;
1248
Eric Andersene494fdd1999-10-19 20:23:03 +00001249 if (argc && *argv)
1250 program_name = *argv;
1251 if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
Eric Andersene674eb71999-10-19 20:52:57 +00001252 die("bad inode size");
Eric Andersene494fdd1999-10-19 20:23:03 +00001253#ifdef HAVE_MINIX2
1254 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
Eric Andersene674eb71999-10-19 20:52:57 +00001255 die("bad v2 inode size");
Eric Andersene494fdd1999-10-19 20:23:03 +00001256#endif
1257 while (argc-- > 1) {
1258 argv++;
1259 if (argv[0][0] != '-') {
1260 if (device_name)
Eric Andersene674eb71999-10-19 20:52:57 +00001261 show_usage();
Eric Andersene494fdd1999-10-19 20:23:03 +00001262 else
1263 device_name = argv[0];
Erik Andersene49d5ec2000-02-08 19:58:47 +00001264 } else
1265 while (*++argv[0])
1266 switch (argv[0][0]) {
1267 case 'l':
1268 list = 1;
1269 break;
1270 case 'a':
1271 automatic = 1;
1272 repair = 1;
1273 break;
1274 case 'r':
1275 automatic = 0;
1276 repair = 1;
1277 break;
1278 case 'v':
1279 verbose = 1;
1280 break;
1281 case 's':
1282 show = 1;
1283 break;
1284 case 'm':
1285 warn_mode = 1;
1286 break;
1287 case 'f':
1288 force = 1;
1289 break;
1290 default:
1291 show_usage();
1292 }
Eric Andersene494fdd1999-10-19 20:23:03 +00001293 }
1294 if (!device_name)
Eric Andersene674eb71999-10-19 20:52:57 +00001295 show_usage();
Erik Andersene49d5ec2000-02-08 19:58:47 +00001296 check_mount(); /* trying to check a mounted filesystem? */
Eric Andersene494fdd1999-10-19 20:23:03 +00001297 if (repair && !automatic) {
1298 if (!isatty(0) || !isatty(1))
Eric Andersene674eb71999-10-19 20:52:57 +00001299 die("need terminal for interactive repairs");
Eric Andersene494fdd1999-10-19 20:23:03 +00001300 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001301 IN = open(device_name, repair ? O_RDWR : O_RDONLY);
Eric Andersene494fdd1999-10-19 20:23:03 +00001302 if (IN < 0)
Eric Andersene674eb71999-10-19 20:52:57 +00001303 die("unable to open '%s'");
Erik Andersene49d5ec2000-02-08 19:58:47 +00001304 for (count = 0; count < 3; count++)
Eric Andersene494fdd1999-10-19 20:23:03 +00001305 sync();
1306 read_superblock();
1307
1308 /*
1309 * Determine whether or not we should continue with the checking.
1310 * This is based on the status of the filesystem valid and error
1311 * flags and whether or not the -f switch was specified on the
1312 * command line.
1313 */
Eric Andersene674eb71999-10-19 20:52:57 +00001314 printf("%s, %s\n", program_name, program_version);
Erik Andersene49d5ec2000-02-08 19:58:47 +00001315 if (!(Super.s_state & MINIX_ERROR_FS) &&
1316 (Super.s_state & MINIX_VALID_FS) && !force) {
Eric Andersene494fdd1999-10-19 20:23:03 +00001317 if (repair)
Eric Andersene674eb71999-10-19 20:52:57 +00001318 printf("%s is clean, no check.\n", device_name);
Eric Andersene494fdd1999-10-19 20:23:03 +00001319 return retcode;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001320 } else if (force)
Eric Andersene674eb71999-10-19 20:52:57 +00001321 printf("Forcing filesystem check on %s.\n", device_name);
Eric Andersene494fdd1999-10-19 20:23:03 +00001322 else if (repair)
Erik Andersene49d5ec2000-02-08 19:58:47 +00001323 printf("Filesystem on %s is dirty, needs checking.\n",
1324 device_name);
Eric Andersene494fdd1999-10-19 20:23:03 +00001325
1326 read_tables();
1327
1328 if (repair && !automatic) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001329 tcgetattr(0, &termios);
Eric Andersene494fdd1999-10-19 20:23:03 +00001330 tmp = termios;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001331 tmp.c_lflag &= ~(ICANON | ECHO);
1332 tcsetattr(0, TCSANOW, &tmp);
Eric Andersene494fdd1999-10-19 20:23:03 +00001333 termios_set = 1;
1334 }
Eric Andersene494fdd1999-10-19 20:23:03 +00001335#if HAVE_MINIX2
1336 if (version2) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001337 check_root2();
1338 check2();
1339 } else
Eric Andersene494fdd1999-10-19 20:23:03 +00001340#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +00001341 {
Eric Andersene494fdd1999-10-19 20:23:03 +00001342 check_root();
1343 check();
1344 }
1345 if (verbose) {
1346 int i, free;
1347
Erik Andersene49d5ec2000-02-08 19:58:47 +00001348 for (i = 1, free = 0; i <= INODES; i++)
Eric Andersene494fdd1999-10-19 20:23:03 +00001349 if (!inode_in_use(i))
1350 free++;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001351 printf("\n%6ld inodes used (%ld%%)\n", (INODES - free),
1352 100 * (INODES - free) / INODES);
1353 for (i = FIRSTZONE, free = 0; i < ZONES; i++)
Eric Andersene494fdd1999-10-19 20:23:03 +00001354 if (!zone_in_use(i))
1355 free++;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001356 printf("%6ld zones used (%ld%%)\n", (ZONES - free),
1357 100 * (ZONES - free) / ZONES);
Eric Andersene674eb71999-10-19 20:52:57 +00001358 printf("\n%6d regular files\n"
Erik Andersene49d5ec2000-02-08 19:58:47 +00001359 "%6d directories\n"
1360 "%6d character device files\n"
1361 "%6d block device files\n"
1362 "%6d links\n"
1363 "%6d symbolic links\n"
1364 "------\n"
1365 "%6d files\n",
1366 regular, directory, chardev, blockdev,
1367 links - 2 * directory + 1, symlinks,
1368 total - 2 * directory + 1);
Eric Andersene494fdd1999-10-19 20:23:03 +00001369 }
1370 if (changed) {
1371 write_tables();
Erik Andersene49d5ec2000-02-08 19:58:47 +00001372 printf("----------------------------\n"
1373 "FILE SYSTEM HAS BEEN CHANGED\n"
1374 "----------------------------\n");
1375 for (count = 0; count < 3; count++)
Eric Andersene494fdd1999-10-19 20:23:03 +00001376 sync();
Erik Andersene49d5ec2000-02-08 19:58:47 +00001377 } else if (repair)
Eric Andersene494fdd1999-10-19 20:23:03 +00001378 write_super_block();
Erik Andersene49d5ec2000-02-08 19:58:47 +00001379
Eric Andersene494fdd1999-10-19 20:23:03 +00001380 if (repair && !automatic)
Erik Andersene49d5ec2000-02-08 19:58:47 +00001381 tcsetattr(0, TCSANOW, &termios);
Eric Andersene494fdd1999-10-19 20:23:03 +00001382
1383 if (changed)
Erik Andersene49d5ec2000-02-08 19:58:47 +00001384 retcode += 3;
Eric Andersene494fdd1999-10-19 20:23:03 +00001385 if (errors_uncorrected)
Erik Andersene49d5ec2000-02-08 19:58:47 +00001386 retcode += 4;
Eric Andersene494fdd1999-10-19 20:23:03 +00001387 return retcode;
1388}