blob: 2ed2b116147484efe2b01e731300aaae45b721d7 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * e2fsck.c - a consistency checker for the new extended file system.
3 *
4 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be
5 * redistributed under the terms of the GNU Public License.
6 */
7
8/* Usage: e2fsck [-dfpnsvy] device
9 * -d -- debugging this program
10 * -f -- check the fs even if it is marked valid
11 * -p -- "preen" the filesystem
12 * -n -- open the filesystem r/o mode; never try to fix problems
13 * -v -- verbose (tells how many files)
14 * -y -- always answer yes to questions
15 *
16 * The device may be a block device or a image of one, but this isn't
17 * enforced (but it's not much fun on a character device :-).
18 */
19
20#include <string.h>
21#include <fcntl.h>
22#include <ctype.h>
23#include <termios.h>
24#include <time.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000025#ifdef HAVE_GETOPT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000026#include <getopt.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000027#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000028#include <unistd.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000029#ifdef HAVE_ERRNO_H
30#include <errno.h>
31#endif
32#ifdef HAVE_MNTENT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000033#include <mntent.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000034#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000035#include <sys/ioctl.h>
36#include <malloc.h>
37
38#include "et/com_err.h"
39#include "e2fsck.h"
40#include "../version.h"
41
42extern int isatty(int);
43
44const char * program_name = "e2fsck";
45const char * device_name = NULL;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000046const char * filesystem_name = NULL;
Theodore Ts'o3839e651997-04-26 13:21:57 +000047
48/* Command line options */
49int nflag = 0;
50int yflag = 0;
51int tflag = 0; /* Do timing */
52int cflag = 0; /* check disk */
53int preen = 0;
54int rwflag = 1;
55int inode_buffer_blocks = 0;
56blk_t superblock;
57int blocksize = 0;
58int verbose = 0;
59int list = 0;
60int debug = 0;
61int force = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +000062int invalid_bitmaps = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +000063static int show_version_only = 0;
64
65static int replace_bad_blocks = 0;
66static char *bad_blocks_file = 0;
67
68static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
69
70struct resource_track global_rtrack;
71
72static int root_filesystem = 0;
73static int read_only_root = 0;
74
Theodore Ts'of3db3561997-04-26 13:34:30 +000075int *invalid_inode_bitmap;
76int *invalid_block_bitmap;
77int *invalid_inode_table;
78int restart_e2fsck = 0;
79
Theodore Ts'o3839e651997-04-26 13:21:57 +000080static void usage(NOARGS)
81{
82 fprintf(stderr,
Theodore Ts'of3db3561997-04-26 13:34:30 +000083 "Usage: %s [-panyrcdfvtFV] [-b superblock] [-B blocksize]\n"
84 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
85 "\t\t[-l|-L bad_blocks_file] device\n", program_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +000086 exit(FSCK_USAGE);
87}
88
89static void show_stats(ext2_filsys fs)
90{
91 int inodes, inodes_used, blocks, blocks_used;
92 int dir_links;
93 int num_files, num_links;
Theodore Ts'o7f88b041997-04-26 14:48:50 +000094 int frag_percent;
Theodore Ts'o3839e651997-04-26 13:21:57 +000095
96 dir_links = 2 * fs_directory_count - 1;
97 num_files = fs_total_count - dir_links;
98 num_links = fs_links_count - dir_links;
99 inodes = fs->super->s_inodes_count;
100 inodes_used = (fs->super->s_inodes_count -
101 fs->super->s_free_inodes_count);
102 blocks = fs->super->s_blocks_count;
103 blocks_used = (fs->super->s_blocks_count -
104 fs->super->s_free_blocks_count);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000105
106 frag_percent = (10000 * fs_fragmented) / inodes_used;
107 frag_percent = (frag_percent + 5) / 10;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000108
109 if (!verbose) {
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000110 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
Theodore Ts'o74becf31997-04-26 14:37:06 +0000111 device_name, inodes_used, inodes,
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000112 frag_percent / 10, frag_percent % 10,
Theodore Ts'o74becf31997-04-26 14:37:06 +0000113 blocks_used, blocks);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000114 return;
115 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000116 printf ("\n%8d inode%s used (%d%%)\n", inodes_used,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000117 (inodes_used != 1) ? "s" : "",
118 100 * inodes_used / inodes);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000119 printf ("%8d non-contiguous inodes (%0d.%d%%)\n",
120 fs_fragmented, frag_percent / 10, frag_percent % 10);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000121 printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n",
122 fs_ind_count, fs_dind_count, fs_tind_count);
123 printf ("%8d block%s used (%d%%)\n"
124 "%8d bad block%s\n", blocks_used,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000125 (blocks_used != 1) ? "s" : "",
126 100 * blocks_used / blocks, fs_badblocks_count,
127 fs_badblocks_count != 1 ? "s" : "");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000128 printf ("\n%8d regular file%s\n"
129 "%8d director%s\n"
130 "%8d character device file%s\n"
131 "%8d block device file%s\n"
132 "%8d fifo%s\n"
133 "%8d link%s\n"
134 "%8d symbolic link%s (%d fast symbolic link%s)\n"
135 "%8d socket%s\n"
136 "--------\n"
137 "%8d file%s\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000138 fs_regular_count, (fs_regular_count != 1) ? "s" : "",
139 fs_directory_count, (fs_directory_count != 1) ? "ies" : "y",
140 fs_chardev_count, (fs_chardev_count != 1) ? "s" : "",
141 fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "",
142 fs_fifo_count, (fs_fifo_count != 1) ? "s" : "",
143 fs_links_count - dir_links,
144 ((fs_links_count - dir_links) != 1) ? "s" : "",
145 fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "",
146 fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "",
147 fs_sockets_count, (fs_sockets_count != 1) ? "s" : "",
148 fs_total_count - dir_links,
149 ((fs_total_count - dir_links) != 1) ? "s" : "");
150}
151
152static void check_mount(NOARGS)
153{
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000154 errcode_t retval;
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000155 int mount_flags, cont, fd;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000156
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000157 retval = ext2fs_check_if_mounted(filesystem_name, &mount_flags);
158 if (retval) {
159 com_err("ext2fs_check_if_mount", retval,
160 "while determining whether %s is mounted.",
161 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000162 return;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000163 }
164 if (!(mount_flags & EXT2_MF_MOUNTED))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000165 return;
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000166
Theodore Ts'o74becf31997-04-26 14:37:06 +0000167#if (defined(__linux__) && defined(HAVE_MNTENT_H))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000168 /*
169 * If the root is mounted read-only, then /etc/mtab is
170 * probably not correct; so we won't issue a warning based on
171 * it.
172 */
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000173 fd = open(MOUNTED, O_RDWR);
174 if (fd < 0) {
175 if (errno == EROFS)
176 return;
177 } else
178 close(fd);
179#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000180
181 if (!rwflag) {
182 printf("Warning! %s is mounted.\n", device_name);
183 return;
184 }
185
186 printf ("%s is mounted. ", device_name);
187 if (isatty (0) && isatty (1))
188 cont = ask_yn("Do you really want to continue", -1);
189 else
190 cont = 0;
191 if (!cont) {
192 printf ("check aborted.\n");
193 exit (0);
194 }
195 return;
196}
197
198static void sync_disks(NOARGS)
199{
200 sync();
201 sync();
202 sleep(1);
203 sync();
204}
205
Theodore Ts'of3db3561997-04-26 13:34:30 +0000206#define MIN_CHECK 1
207#define MAX_CHECK 2
208
209static const char *corrupt_msg = "\nThe filesystem superblock is corrupt. "
210 "Try running e2fsck with an alternate\n"
211 "superblock using the -b option. "
212 "(8193 is commonly an alternate superblock;\n"
213 "Hence, 'e2fsck -b 8193 <device>' may recover the filesystem.)\n\n";
214
215static void check_super_value(const char *descr, unsigned long value,
216 int flags, unsigned long min, unsigned long max)
217{
218 if (((flags & MIN_CHECK) && (value < min)) ||
219 ((flags & MAX_CHECK) && (value > max))) {
220 printf("Corruption found in superblock. (%s = %lu).\n",
221 descr, value);
222 printf(corrupt_msg);
223 fatal_error(0);
224 }
225}
226
Theodore Ts'o3839e651997-04-26 13:21:57 +0000227static void check_super_block(ext2_filsys fs)
228{
229 blk_t first_block, last_block;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000230 struct ext2_super_block *s = fs->super;
231 blk_t blocks_per_group = fs->super->s_blocks_per_group;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000232 int i;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000233 blk_t should_be;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000234 errcode_t retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000235
Theodore Ts'of3db3561997-04-26 13:34:30 +0000236 /*
237 * Verify the super block constants...
238 */
239 check_super_value("inodes_count", s->s_inodes_count,
240 MIN_CHECK, 1, 0);
241 check_super_value("blocks_count", s->s_blocks_count,
242 MIN_CHECK, 1, 0);
243 check_super_value("first_data_block", s->s_first_data_block,
244 MAX_CHECK, 0, s->s_blocks_count);
245 check_super_value("log_frag_size", s->s_log_frag_size,
246 MAX_CHECK, 0, 2);
247 check_super_value("log_block_size", s->s_log_block_size,
248 MIN_CHECK | MAX_CHECK, s->s_log_frag_size,
249 2);
250 check_super_value("frags_per_group", s->s_frags_per_group,
251 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
252 check_super_value("blocks_per_group", s->s_blocks_per_group,
253 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
254 check_super_value("inodes_per_group", s->s_inodes_per_group,
255 MIN_CHECK, 1, 0);
256 check_super_value("r_blocks_count", s->s_r_blocks_count,
257 MAX_CHECK, 0, s->s_blocks_count);
258
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000259 retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s),
260 &should_be);
261 if (retval) {
262 com_err("ext2fs_get_device_size", retval,
263 "while trying to check physical size of filesystem");
264 fatal_error(0);
265 }
266 if (should_be < s->s_blocks_count) {
267 printf("The filesystem size (according to the superblock) is %d blocks\n", s->s_blocks_count);
268 printf("The physical size of the device is %d blocks\n",
269 should_be);
270 printf("Either the superblock or the partition table is likely to be corrupt!\n");
271 preenhalt(fs);
272 if (ask("Abort", 1))
273 fatal_error(0);
274 }
275
Theodore Ts'of3db3561997-04-26 13:34:30 +0000276 if (s->s_log_block_size != s->s_log_frag_size) {
277 printf("Superblock block_size = %d, fragsize = %d.\n",
278 EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s));
279 printf("This version of e2fsck does not support fragment "
280 "sizes different\n"
281 "from the block size.\n");
282 fatal_error(0);
283 }
284
285 should_be = s->s_frags_per_group /
286 (s->s_log_block_size - s->s_log_frag_size + 1);
287 if (s->s_blocks_per_group != should_be) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000288 printf("Superblock blocks_per_group = %u, should "
289 "have been %u\n", s->s_blocks_per_group,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000290 should_be);
291 printf(corrupt_msg);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000292 fatal_error(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000293 }
294
295 should_be = (s->s_log_block_size == 0) ? 1 : 0;
296 if (s->s_first_data_block != should_be) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000297 printf("Superblock first_data_block = %u, should "
298 "have been %u\n", s->s_first_data_block,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000299 should_be);
300 printf(corrupt_msg);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000301 fatal_error(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000302 }
303
304 /*
305 * Verify the group descriptors....
306 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000307 first_block = fs->super->s_first_data_block;
308 last_block = first_block + blocks_per_group;
309
310 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000311 if (i == fs->group_desc_count - 1)
312 last_block = fs->super->s_blocks_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000313 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
314 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000315 printf("Block bitmap for group %d is not in group. "
316 "(block %u)\n",
317 i, fs->group_desc[i].bg_block_bitmap);
318 preenhalt(fs);
319 if (!ask("Relocate", 1)) {
320 fatal_error("Block bitmap not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000321 }
322 fs->group_desc[i].bg_block_bitmap = 0;
323 invalid_block_bitmap[i]++;
324 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000325 }
326 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
327 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000328 printf("Inode bitmap group %d not in group. "
329 "(block %u)\n",
330 i, fs->group_desc[i].bg_inode_bitmap);
331 preenhalt(fs);
332 if (!ask("Relocate", 1)) {
333 fatal_error("Inode bitmap not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000334 }
335 fs->group_desc[i].bg_inode_bitmap = 0;
336 invalid_inode_bitmap[i]++;
337 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000338 }
339 if ((fs->group_desc[i].bg_inode_table < first_block) ||
340 ((fs->group_desc[i].bg_inode_table +
341 fs->inode_blocks_per_group - 1) >= last_block)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000342 printf("Inode table for group %d not in group. "
343 "(block %u)\n",
344 i, fs->group_desc[i].bg_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000345 printf("WARNING: SEVERE DATA LOSS POSSIBLE.\n");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000346 preenhalt(fs);
347 if (!ask("Relocate", 1)) {
348 fatal_error("Inode table not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000349 }
350 fs->group_desc[i].bg_inode_table = 0;
351 invalid_inode_table[i]++;
352 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000353 }
354 first_block += fs->super->s_blocks_per_group;
355 last_block += fs->super->s_blocks_per_group;
356 }
357 return;
358}
359
360/*
361 * This routine checks to see if a filesystem can be skipped; if so,
362 * it will exit with E2FSCK_OK. Under some conditions it will print a
363 * message explaining why a check is being forced.
364 */
365static void check_if_skip(ext2_filsys fs)
366{
367 const char *reason = NULL;
368
369 if (force || bad_blocks_file || cflag)
370 return;
371
372 if (fs->super->s_state & EXT2_ERROR_FS)
373 reason = "contains a file system with errors";
374 else if (fs->super->s_mnt_count >=
375 (unsigned) fs->super->s_max_mnt_count)
376 reason = "has reached maximal mount count";
377 else if (fs->super->s_checkinterval &&
378 time(0) >= (fs->super->s_lastcheck +
379 fs->super->s_checkinterval))
380 reason = "has gone too long without being checked";
381 if (reason) {
382 printf("%s %s, check forced.\n", device_name, reason);
383 return;
384 }
385 if (fs->super->s_state & EXT2_VALID_FS) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000386 printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name,
387 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
388 fs->super->s_inodes_count,
389 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
390 fs->super->s_blocks_count);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000391 exit(FSCK_OK);
392 }
393}
394
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000395#define PATH_SET "PATH=/sbin"
396
Theodore Ts'o3839e651997-04-26 13:21:57 +0000397static void PRS(int argc, char *argv[])
398{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000399 int flush = 0;
400 char c;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000401#ifdef MTRACE
Theodore Ts'of3db3561997-04-26 13:34:30 +0000402 extern void *mallwatch;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000403#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000404 char *oldpath = getenv("PATH");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000405
406 /* Update our PATH to include /sbin */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000407 if (oldpath) {
408 char *newpath;
409
410 newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
411 if (!newpath)
412 fatal_error("Couldn't malloc() newpath");
413 strcpy (newpath, PATH_SET);
414 strcat (newpath, ":");
415 strcat (newpath, oldpath);
416 putenv (newpath);
417 } else
418 putenv (PATH_SET);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000419
420 setbuf(stdout, NULL);
421 setbuf(stderr, NULL);
422 initialize_ext2_error_table();
423
424 if (argc && *argv)
425 program_name = *argv;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000426 while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:")) != EOF)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000427 switch (c) {
428 case 'p':
429 case 'a':
430 preen = 1;
431 yflag = nflag = 0;
432 break;
433 case 'n':
434 nflag = 1;
435 preen = yflag = 0;
436 break;
437 case 'y':
438 yflag = 1;
439 preen = nflag = 0;
440 break;
441 case 't':
442 tflag++;
443 break;
444 case 'c':
445 cflag++;
446 break;
447 case 'r':
448 /* What we do by default, anyway! */
449 break;
450 case 'b':
451 superblock = atoi(optarg);
452 break;
453 case 'B':
454 blocksize = atoi(optarg);
455 break;
456 case 'I':
457 inode_buffer_blocks = atoi(optarg);
458 break;
459 case 'P':
460 process_inode_size = atoi(optarg);
461 break;
462 case 'L':
463 replace_bad_blocks++;
464 case 'l':
465 bad_blocks_file = malloc(strlen(optarg)+1);
466 if (!bad_blocks_file)
467 fatal_error("Couldn't malloc bad_blocks_file");
468 strcpy(bad_blocks_file, optarg);
469 break;
470 case 'd':
471 debug = 1;
472 break;
473 case 'f':
474 force = 1;
475 break;
476 case 'F':
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000477#ifdef BLKFLSBUF
Theodore Ts'o3839e651997-04-26 13:21:57 +0000478 flush = 1;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000479#else
480 fatal_error ("-F not supported");
481#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000482 break;
483 case 'v':
484 verbose = 1;
485 break;
486 case 'V':
487 show_version_only = 1;
488 break;
489#ifdef MTRACE
490 case 'M':
491 mallwatch = (void *) strtol(optarg, NULL, 0);
492 break;
493#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000494 case 'N':
495 device_name = optarg;
496 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000497 default:
498 usage ();
499 }
500 if (show_version_only)
501 return;
502 if (optind != argc - 1)
503 usage ();
504 if (nflag && !bad_blocks_file && !cflag)
505 rwflag = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000506 filesystem_name = argv[optind];
507 if (device_name == 0)
508 device_name = filesystem_name;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000509 if (flush) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000510#ifdef BLKFLSBUF
511 int fd = open(filesystem_name, O_RDONLY, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000512
513 if (fd < 0) {
514 com_err("open", errno, "while opening %s for flushing",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000515 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000516 exit(FSCK_ERROR);
517 }
518 if (ioctl(fd, BLKFLSBUF, 0) < 0) {
519 com_err("BLKFLSBUF", errno, "while trying to flush %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000520 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000521 exit(FSCK_ERROR);
522 }
523 close(fd);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000524#else
525 fatal_error ("BLKFLSBUF not supported");
526#endif /* BLKFLSBUF */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000527 }
528}
529
530int main (int argc, char *argv[])
531{
532 errcode_t retval = 0;
533 int exit_value = FSCK_OK;
534 int i;
535 ext2_filsys fs;
536
537#ifdef MTRACE
538 mtrace();
539#endif
540#ifdef MCHECK
541 mcheck(0);
542#endif
543
544 init_resource_track(&global_rtrack);
545
546 PRS(argc, argv);
547
548 if (!preen)
549 fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
550 E2FSPROGS_VERSION, E2FSPROGS_DATE,
551 EXT2FS_VERSION, EXT2FS_DATE);
552
553 if (show_version_only)
554 exit(0);
555
556 check_mount();
557
558 if (!preen && !nflag && !yflag) {
559 if (!isatty (0) || !isatty (1))
560 die ("need terminal for interactive repairs");
561 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000562restart:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000563 sync_disks();
564 if (superblock && blocksize) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000565 retval = ext2fs_open(filesystem_name,
566 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000567 superblock, blocksize, unix_io_manager,
568 &fs);
569 } else if (superblock) {
570 for (i=0; possible_block_sizes[i]; i++) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000571 retval = ext2fs_open(filesystem_name,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000572 rwflag ? EXT2_FLAG_RW : 0,
573 superblock,
574 possible_block_sizes[i],
575 unix_io_manager, &fs);
576 if (!retval)
577 break;
578 }
579 } else
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000580 retval = ext2fs_open(filesystem_name,
581 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000582 0, 0, unix_io_manager, &fs);
583 if (retval) {
584 com_err(program_name, retval, "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000585 filesystem_name);
586 switch (retval) {
587 case EXT2_ET_REV_TOO_HIGH:
Theodore Ts'of3db3561997-04-26 13:34:30 +0000588 printf ("Get a newer version of e2fsck!\n");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000589 break;
590 case EXT2_ET_SHORT_READ:
591 printf ("Could this be a zero-length partition?\n");
592 break;
593 case EPERM:
594 case EACCES:
595 printf("You must have %s access to the "
596 "filesystem or be root\n",
597 rwflag ? "r/w" : "r/o");
598 break;
599 case ENXIO:
600 printf("Possibly non-existent or swap device?\n");
601 break;
602 default:
Theodore Ts'of3db3561997-04-26 13:34:30 +0000603 printf(corrupt_msg);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000604 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000605 fatal_error(0);
606 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000607
608#ifdef EXT2_CURRENT_REV
609 if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000610 com_err(program_name, EXT2_ET_REV_TOO_HIGH,
611 "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000612 filesystem_name);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000613 printf ("Get a newer version of e2fsck!\n");
614 fatal_error(0);
615 }
616#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000617 /*
618 * If the user specified a specific superblock, presumably the
619 * master superblock has been trashed. So we mark the
620 * superblock as dirty, so it can be written out.
621 */
622 if (superblock && rwflag)
623 ext2fs_mark_super_dirty(fs);
624
625 ehandler_init(fs->io);
626
Theodore Ts'of3db3561997-04-26 13:34:30 +0000627 invalid_inode_bitmap = allocate_memory(sizeof(int) *
628 fs->group_desc_count,
629 "invalid_inode_bitmap");
630 invalid_block_bitmap = allocate_memory(sizeof(int) *
631 fs->group_desc_count,
632 "invalid_block_bitmap");
633 invalid_inode_table = allocate_memory(sizeof(int) *
634 fs->group_desc_count,
635 "invalid_inode_table");
636
Theodore Ts'o3839e651997-04-26 13:21:57 +0000637 check_super_block(fs);
638 check_if_skip(fs);
639 if (bad_blocks_file)
640 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
641 else if (cflag)
642 test_disk(fs);
643
644 /*
645 * Mark the system as valid, 'til proven otherwise
646 */
647 ext2fs_mark_valid(fs);
648
649 pass1(fs);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000650 free(invalid_inode_bitmap);
651 free(invalid_block_bitmap);
652 free(invalid_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000653 if (restart_e2fsck) {
654 ext2fs_close(fs);
655 printf("Restarting e2fsck from the beginning...\n");
656 restart_e2fsck = 0;
657 goto restart;
658 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000659 pass2(fs);
660 pass3(fs);
661 pass4(fs);
662 pass5(fs);
663
664#ifdef MTRACE
665 mtrace_print("Cleanup");
666#endif
667 if (ext2fs_test_changed(fs)) {
668 exit_value = FSCK_NONDESTRUCT;
669 if (!preen)
670 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
671 device_name);
672 if (root_filesystem && !read_only_root) {
673 printf("%s: ***** REBOOT LINUX *****\n", device_name);
674 exit_value = FSCK_REBOOT;
675 }
676 }
677 if (!ext2fs_test_valid(fs))
678 exit_value = FSCK_UNCORRECTED;
679 if (rwflag) {
680 if (ext2fs_test_valid(fs))
681 fs->super->s_state = EXT2_VALID_FS;
682 else
683 fs->super->s_state &= ~EXT2_VALID_FS;
684 fs->super->s_mnt_count = 0;
685 fs->super->s_lastcheck = time(NULL);
686 ext2fs_mark_super_dirty(fs);
687 }
688 show_stats(fs);
689
690 write_bitmaps(fs);
691 ext2fs_close(fs);
692 sync_disks();
693
694 if (tflag)
695 print_resource_track(&global_rtrack);
696
697 return exit_value;
698}