blob: 6dbfa6f0633378626623244668d45a88168af2f3 [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'o62c06f71997-04-29 14:34:47 +0000227static void relocate_hint()
228{
229 static hint_issued = 0;
230
231 /* Only issue the hint once */
232 if (hint_issued)
233 return;
234
235 printf("Note: if there is several inode or block bitmap blocks\n"
236 "which require relocation, or one part of the inode table\n"
237 "which must be moved, you may wish to try running e2fsck\n"
238 "the '-b 8193' option first. The problem may lie only with\n"
239 "the primary block group descriptor, and the backup block\n"
240 "group descriptor may be OK.\n\n");
241 hint_issued = 1;
242}
243
244
Theodore Ts'o3839e651997-04-26 13:21:57 +0000245static void check_super_block(ext2_filsys fs)
246{
247 blk_t first_block, last_block;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000248 struct ext2_super_block *s = fs->super;
249 blk_t blocks_per_group = fs->super->s_blocks_per_group;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000250 int i;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000251 blk_t should_be;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000252 errcode_t retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000253
Theodore Ts'of3db3561997-04-26 13:34:30 +0000254 /*
255 * Verify the super block constants...
256 */
257 check_super_value("inodes_count", s->s_inodes_count,
258 MIN_CHECK, 1, 0);
259 check_super_value("blocks_count", s->s_blocks_count,
260 MIN_CHECK, 1, 0);
261 check_super_value("first_data_block", s->s_first_data_block,
262 MAX_CHECK, 0, s->s_blocks_count);
263 check_super_value("log_frag_size", s->s_log_frag_size,
264 MAX_CHECK, 0, 2);
265 check_super_value("log_block_size", s->s_log_block_size,
266 MIN_CHECK | MAX_CHECK, s->s_log_frag_size,
267 2);
268 check_super_value("frags_per_group", s->s_frags_per_group,
269 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
270 check_super_value("blocks_per_group", s->s_blocks_per_group,
271 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
272 check_super_value("inodes_per_group", s->s_inodes_per_group,
273 MIN_CHECK, 1, 0);
274 check_super_value("r_blocks_count", s->s_r_blocks_count,
275 MAX_CHECK, 0, s->s_blocks_count);
276
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000277 retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s),
278 &should_be);
279 if (retval) {
280 com_err("ext2fs_get_device_size", retval,
281 "while trying to check physical size of filesystem");
282 fatal_error(0);
283 }
284 if (should_be < s->s_blocks_count) {
285 printf("The filesystem size (according to the superblock) is %d blocks\n", s->s_blocks_count);
286 printf("The physical size of the device is %d blocks\n",
287 should_be);
288 printf("Either the superblock or the partition table is likely to be corrupt!\n");
289 preenhalt(fs);
290 if (ask("Abort", 1))
291 fatal_error(0);
292 }
293
Theodore Ts'of3db3561997-04-26 13:34:30 +0000294 if (s->s_log_block_size != s->s_log_frag_size) {
295 printf("Superblock block_size = %d, fragsize = %d.\n",
296 EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s));
297 printf("This version of e2fsck does not support fragment "
298 "sizes different\n"
299 "from the block size.\n");
300 fatal_error(0);
301 }
302
303 should_be = s->s_frags_per_group /
304 (s->s_log_block_size - s->s_log_frag_size + 1);
305 if (s->s_blocks_per_group != should_be) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000306 printf("Superblock blocks_per_group = %u, should "
307 "have been %u\n", s->s_blocks_per_group,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000308 should_be);
309 printf(corrupt_msg);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000310 fatal_error(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000311 }
312
313 should_be = (s->s_log_block_size == 0) ? 1 : 0;
314 if (s->s_first_data_block != should_be) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000315 printf("Superblock first_data_block = %u, should "
316 "have been %u\n", s->s_first_data_block,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000317 should_be);
318 printf(corrupt_msg);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000319 fatal_error(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000320 }
321
322 /*
323 * Verify the group descriptors....
324 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000325 first_block = fs->super->s_first_data_block;
326 last_block = first_block + blocks_per_group;
327
328 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000329 if (i == fs->group_desc_count - 1)
330 last_block = fs->super->s_blocks_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000331 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
332 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000333 relocate_hint();
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000334 printf("Block bitmap for group %d is not in group. "
335 "(block %u)\n",
336 i, fs->group_desc[i].bg_block_bitmap);
337 preenhalt(fs);
338 if (!ask("Relocate", 1)) {
339 fatal_error("Block bitmap not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000340 }
341 fs->group_desc[i].bg_block_bitmap = 0;
342 invalid_block_bitmap[i]++;
343 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000344 }
345 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
346 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000347 relocate_hint();
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000348 printf("Inode bitmap group %d not in group. "
349 "(block %u)\n",
350 i, fs->group_desc[i].bg_inode_bitmap);
351 preenhalt(fs);
352 if (!ask("Relocate", 1)) {
353 fatal_error("Inode bitmap not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000354 }
355 fs->group_desc[i].bg_inode_bitmap = 0;
356 invalid_inode_bitmap[i]++;
357 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000358 }
359 if ((fs->group_desc[i].bg_inode_table < first_block) ||
360 ((fs->group_desc[i].bg_inode_table +
361 fs->inode_blocks_per_group - 1) >= last_block)) {
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000362 relocate_hint();
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000363 printf("Inode table for group %d not in group. "
364 "(block %u)\n",
365 i, fs->group_desc[i].bg_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000366 printf("WARNING: SEVERE DATA LOSS POSSIBLE.\n");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000367 preenhalt(fs);
368 if (!ask("Relocate", 1)) {
369 fatal_error("Inode table not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000370 }
371 fs->group_desc[i].bg_inode_table = 0;
372 invalid_inode_table[i]++;
373 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000374 }
375 first_block += fs->super->s_blocks_per_group;
376 last_block += fs->super->s_blocks_per_group;
377 }
378 return;
379}
380
381/*
382 * This routine checks to see if a filesystem can be skipped; if so,
383 * it will exit with E2FSCK_OK. Under some conditions it will print a
384 * message explaining why a check is being forced.
385 */
386static void check_if_skip(ext2_filsys fs)
387{
388 const char *reason = NULL;
389
390 if (force || bad_blocks_file || cflag)
391 return;
392
393 if (fs->super->s_state & EXT2_ERROR_FS)
394 reason = "contains a file system with errors";
395 else if (fs->super->s_mnt_count >=
396 (unsigned) fs->super->s_max_mnt_count)
397 reason = "has reached maximal mount count";
398 else if (fs->super->s_checkinterval &&
399 time(0) >= (fs->super->s_lastcheck +
400 fs->super->s_checkinterval))
401 reason = "has gone too long without being checked";
402 if (reason) {
403 printf("%s %s, check forced.\n", device_name, reason);
404 return;
405 }
406 if (fs->super->s_state & EXT2_VALID_FS) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000407 printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name,
408 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
409 fs->super->s_inodes_count,
410 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
411 fs->super->s_blocks_count);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000412 exit(FSCK_OK);
413 }
414}
415
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000416#define PATH_SET "PATH=/sbin"
417
Theodore Ts'o3839e651997-04-26 13:21:57 +0000418static void PRS(int argc, char *argv[])
419{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000420 int flush = 0;
421 char c;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000422#ifdef MTRACE
Theodore Ts'of3db3561997-04-26 13:34:30 +0000423 extern void *mallwatch;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000424#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000425 char *oldpath = getenv("PATH");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000426
427 /* Update our PATH to include /sbin */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000428 if (oldpath) {
429 char *newpath;
430
431 newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
432 if (!newpath)
433 fatal_error("Couldn't malloc() newpath");
434 strcpy (newpath, PATH_SET);
435 strcat (newpath, ":");
436 strcat (newpath, oldpath);
437 putenv (newpath);
438 } else
439 putenv (PATH_SET);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000440
441 setbuf(stdout, NULL);
442 setbuf(stderr, NULL);
443 initialize_ext2_error_table();
444
445 if (argc && *argv)
446 program_name = *argv;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000447 while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:")) != EOF)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000448 switch (c) {
449 case 'p':
450 case 'a':
451 preen = 1;
452 yflag = nflag = 0;
453 break;
454 case 'n':
455 nflag = 1;
456 preen = yflag = 0;
457 break;
458 case 'y':
459 yflag = 1;
460 preen = nflag = 0;
461 break;
462 case 't':
463 tflag++;
464 break;
465 case 'c':
466 cflag++;
467 break;
468 case 'r':
469 /* What we do by default, anyway! */
470 break;
471 case 'b':
472 superblock = atoi(optarg);
473 break;
474 case 'B':
475 blocksize = atoi(optarg);
476 break;
477 case 'I':
478 inode_buffer_blocks = atoi(optarg);
479 break;
480 case 'P':
481 process_inode_size = atoi(optarg);
482 break;
483 case 'L':
484 replace_bad_blocks++;
485 case 'l':
486 bad_blocks_file = malloc(strlen(optarg)+1);
487 if (!bad_blocks_file)
488 fatal_error("Couldn't malloc bad_blocks_file");
489 strcpy(bad_blocks_file, optarg);
490 break;
491 case 'd':
492 debug = 1;
493 break;
494 case 'f':
495 force = 1;
496 break;
497 case 'F':
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000498#ifdef BLKFLSBUF
Theodore Ts'o3839e651997-04-26 13:21:57 +0000499 flush = 1;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000500#else
501 fatal_error ("-F not supported");
502#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000503 break;
504 case 'v':
505 verbose = 1;
506 break;
507 case 'V':
508 show_version_only = 1;
509 break;
510#ifdef MTRACE
511 case 'M':
512 mallwatch = (void *) strtol(optarg, NULL, 0);
513 break;
514#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000515 case 'N':
516 device_name = optarg;
517 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000518 default:
519 usage ();
520 }
521 if (show_version_only)
522 return;
523 if (optind != argc - 1)
524 usage ();
525 if (nflag && !bad_blocks_file && !cflag)
526 rwflag = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000527 filesystem_name = argv[optind];
528 if (device_name == 0)
529 device_name = filesystem_name;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000530 if (flush) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000531#ifdef BLKFLSBUF
532 int fd = open(filesystem_name, O_RDONLY, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000533
534 if (fd < 0) {
535 com_err("open", errno, "while opening %s for flushing",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000536 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000537 exit(FSCK_ERROR);
538 }
539 if (ioctl(fd, BLKFLSBUF, 0) < 0) {
540 com_err("BLKFLSBUF", errno, "while trying to flush %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000541 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000542 exit(FSCK_ERROR);
543 }
544 close(fd);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000545#else
546 fatal_error ("BLKFLSBUF not supported");
547#endif /* BLKFLSBUF */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000548 }
549}
550
551int main (int argc, char *argv[])
552{
553 errcode_t retval = 0;
554 int exit_value = FSCK_OK;
555 int i;
556 ext2_filsys fs;
557
558#ifdef MTRACE
559 mtrace();
560#endif
561#ifdef MCHECK
562 mcheck(0);
563#endif
564
565 init_resource_track(&global_rtrack);
566
567 PRS(argc, argv);
568
569 if (!preen)
570 fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
571 E2FSPROGS_VERSION, E2FSPROGS_DATE,
572 EXT2FS_VERSION, EXT2FS_DATE);
573
574 if (show_version_only)
575 exit(0);
576
577 check_mount();
578
579 if (!preen && !nflag && !yflag) {
580 if (!isatty (0) || !isatty (1))
581 die ("need terminal for interactive repairs");
582 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000583restart:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000584 sync_disks();
585 if (superblock && blocksize) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000586 retval = ext2fs_open(filesystem_name,
587 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000588 superblock, blocksize, unix_io_manager,
589 &fs);
590 } else if (superblock) {
591 for (i=0; possible_block_sizes[i]; i++) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000592 retval = ext2fs_open(filesystem_name,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000593 rwflag ? EXT2_FLAG_RW : 0,
594 superblock,
595 possible_block_sizes[i],
596 unix_io_manager, &fs);
597 if (!retval)
598 break;
599 }
600 } else
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000601 retval = ext2fs_open(filesystem_name,
602 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000603 0, 0, unix_io_manager, &fs);
604 if (retval) {
605 com_err(program_name, retval, "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000606 filesystem_name);
607 switch (retval) {
608 case EXT2_ET_REV_TOO_HIGH:
Theodore Ts'of3db3561997-04-26 13:34:30 +0000609 printf ("Get a newer version of e2fsck!\n");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000610 break;
611 case EXT2_ET_SHORT_READ:
612 printf ("Could this be a zero-length partition?\n");
613 break;
614 case EPERM:
615 case EACCES:
616 printf("You must have %s access to the "
617 "filesystem or be root\n",
618 rwflag ? "r/w" : "r/o");
619 break;
620 case ENXIO:
621 printf("Possibly non-existent or swap device?\n");
622 break;
623 default:
Theodore Ts'of3db3561997-04-26 13:34:30 +0000624 printf(corrupt_msg);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000625 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000626 fatal_error(0);
627 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000628
629#ifdef EXT2_CURRENT_REV
630 if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000631 com_err(program_name, EXT2_ET_REV_TOO_HIGH,
632 "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000633 filesystem_name);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000634 printf ("Get a newer version of e2fsck!\n");
635 fatal_error(0);
636 }
637#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000638 /*
639 * If the user specified a specific superblock, presumably the
640 * master superblock has been trashed. So we mark the
641 * superblock as dirty, so it can be written out.
642 */
643 if (superblock && rwflag)
644 ext2fs_mark_super_dirty(fs);
645
646 ehandler_init(fs->io);
647
Theodore Ts'of3db3561997-04-26 13:34:30 +0000648 invalid_inode_bitmap = allocate_memory(sizeof(int) *
649 fs->group_desc_count,
650 "invalid_inode_bitmap");
651 invalid_block_bitmap = allocate_memory(sizeof(int) *
652 fs->group_desc_count,
653 "invalid_block_bitmap");
654 invalid_inode_table = allocate_memory(sizeof(int) *
655 fs->group_desc_count,
656 "invalid_inode_table");
657
Theodore Ts'o3839e651997-04-26 13:21:57 +0000658 check_super_block(fs);
659 check_if_skip(fs);
660 if (bad_blocks_file)
661 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
662 else if (cflag)
663 test_disk(fs);
664
665 /*
666 * Mark the system as valid, 'til proven otherwise
667 */
668 ext2fs_mark_valid(fs);
669
670 pass1(fs);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000671 free(invalid_inode_bitmap);
672 free(invalid_block_bitmap);
673 free(invalid_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000674 if (restart_e2fsck) {
675 ext2fs_close(fs);
676 printf("Restarting e2fsck from the beginning...\n");
677 restart_e2fsck = 0;
678 goto restart;
679 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000680 pass2(fs);
681 pass3(fs);
682 pass4(fs);
683 pass5(fs);
684
685#ifdef MTRACE
686 mtrace_print("Cleanup");
687#endif
688 if (ext2fs_test_changed(fs)) {
689 exit_value = FSCK_NONDESTRUCT;
690 if (!preen)
691 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
692 device_name);
693 if (root_filesystem && !read_only_root) {
694 printf("%s: ***** REBOOT LINUX *****\n", device_name);
695 exit_value = FSCK_REBOOT;
696 }
697 }
698 if (!ext2fs_test_valid(fs))
699 exit_value = FSCK_UNCORRECTED;
700 if (rwflag) {
701 if (ext2fs_test_valid(fs))
702 fs->super->s_state = EXT2_VALID_FS;
703 else
704 fs->super->s_state &= ~EXT2_VALID_FS;
705 fs->super->s_mnt_count = 0;
706 fs->super->s_lastcheck = time(NULL);
707 ext2fs_mark_super_dirty(fs);
708 }
709 show_stats(fs);
710
711 write_bitmaps(fs);
712 ext2fs_close(fs);
713 sync_disks();
714
715 if (tflag)
716 print_resource_track(&global_rtrack);
717
718 return exit_value;
719}