blob: f081d6689c05bbc201cefd0b3f834c14295c9aeb [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
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000020#include <stdio.h>
21#ifdef HAVE_STDLIB_H
22#include <stdlib.h>
23#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000024#include <string.h>
25#include <fcntl.h>
26#include <ctype.h>
27#include <termios.h>
28#include <time.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000029#ifdef HAVE_GETOPT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000030#include <getopt.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000031#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000032#include <unistd.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000033#ifdef HAVE_ERRNO_H
34#include <errno.h>
35#endif
36#ifdef HAVE_MNTENT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000037#include <mntent.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000038#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000039#include <sys/ioctl.h>
40#include <malloc.h>
41
42#include "et/com_err.h"
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000043#include "uuid/uuid.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000044#include "e2fsck.h"
45#include "../version.h"
46
47extern int isatty(int);
48
49const char * program_name = "e2fsck";
50const char * device_name = NULL;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000051const char * filesystem_name = NULL;
Theodore Ts'o3839e651997-04-26 13:21:57 +000052
53/* Command line options */
54int nflag = 0;
55int yflag = 0;
56int tflag = 0; /* Do timing */
57int cflag = 0; /* check disk */
58int preen = 0;
59int rwflag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000060int swapfs = 0;
61int normalize_swapfs = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +000062int inode_buffer_blocks = 0;
63blk_t superblock;
64int blocksize = 0;
65int verbose = 0;
66int list = 0;
67int debug = 0;
68int force = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +000069int invalid_bitmaps = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +000070static int show_version_only = 0;
71
72static int replace_bad_blocks = 0;
73static char *bad_blocks_file = 0;
74
75static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
76
77struct resource_track global_rtrack;
78
79static int root_filesystem = 0;
80static int read_only_root = 0;
81
Theodore Ts'of3db3561997-04-26 13:34:30 +000082int *invalid_inode_bitmap;
83int *invalid_block_bitmap;
84int *invalid_inode_table;
85int restart_e2fsck = 0;
86
Theodore Ts'o3839e651997-04-26 13:21:57 +000087static void usage(NOARGS)
88{
89 fprintf(stderr,
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000090 "Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n"
Theodore Ts'of3db3561997-04-26 13:34:30 +000091 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
92 "\t\t[-l|-L bad_blocks_file] device\n", program_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +000093 exit(FSCK_USAGE);
94}
95
96static void show_stats(ext2_filsys fs)
97{
98 int inodes, inodes_used, blocks, blocks_used;
99 int dir_links;
100 int num_files, num_links;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000101 int frag_percent;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000102
103 dir_links = 2 * fs_directory_count - 1;
104 num_files = fs_total_count - dir_links;
105 num_links = fs_links_count - dir_links;
106 inodes = fs->super->s_inodes_count;
107 inodes_used = (fs->super->s_inodes_count -
108 fs->super->s_free_inodes_count);
109 blocks = fs->super->s_blocks_count;
110 blocks_used = (fs->super->s_blocks_count -
111 fs->super->s_free_blocks_count);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000112
113 frag_percent = (10000 * fs_fragmented) / inodes_used;
114 frag_percent = (frag_percent + 5) / 10;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000115
116 if (!verbose) {
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000117 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
Theodore Ts'o74becf31997-04-26 14:37:06 +0000118 device_name, inodes_used, inodes,
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000119 frag_percent / 10, frag_percent % 10,
Theodore Ts'o74becf31997-04-26 14:37:06 +0000120 blocks_used, blocks);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000121 return;
122 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000123 printf ("\n%8d inode%s used (%d%%)\n", inodes_used,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000124 (inodes_used != 1) ? "s" : "",
125 100 * inodes_used / inodes);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000126 printf ("%8d non-contiguous inodes (%0d.%d%%)\n",
127 fs_fragmented, frag_percent / 10, frag_percent % 10);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000128 printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n",
129 fs_ind_count, fs_dind_count, fs_tind_count);
130 printf ("%8d block%s used (%d%%)\n"
131 "%8d bad block%s\n", blocks_used,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000132 (blocks_used != 1) ? "s" : "",
133 100 * blocks_used / blocks, fs_badblocks_count,
134 fs_badblocks_count != 1 ? "s" : "");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000135 printf ("\n%8d regular file%s\n"
136 "%8d director%s\n"
137 "%8d character device file%s\n"
138 "%8d block device file%s\n"
139 "%8d fifo%s\n"
140 "%8d link%s\n"
141 "%8d symbolic link%s (%d fast symbolic link%s)\n"
142 "%8d socket%s\n"
143 "--------\n"
144 "%8d file%s\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000145 fs_regular_count, (fs_regular_count != 1) ? "s" : "",
146 fs_directory_count, (fs_directory_count != 1) ? "ies" : "y",
147 fs_chardev_count, (fs_chardev_count != 1) ? "s" : "",
148 fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "",
149 fs_fifo_count, (fs_fifo_count != 1) ? "s" : "",
150 fs_links_count - dir_links,
151 ((fs_links_count - dir_links) != 1) ? "s" : "",
152 fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "",
153 fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "",
154 fs_sockets_count, (fs_sockets_count != 1) ? "s" : "",
155 fs_total_count - dir_links,
156 ((fs_total_count - dir_links) != 1) ? "s" : "");
157}
158
159static void check_mount(NOARGS)
160{
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000161 errcode_t retval;
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000162 int mount_flags, cont, fd;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000163
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000164 retval = ext2fs_check_if_mounted(filesystem_name, &mount_flags);
165 if (retval) {
166 com_err("ext2fs_check_if_mount", retval,
167 "while determining whether %s is mounted.",
168 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000169 return;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000170 }
171 if (!(mount_flags & EXT2_MF_MOUNTED))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000172 return;
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000173
Theodore Ts'o74becf31997-04-26 14:37:06 +0000174#if (defined(__linux__) && defined(HAVE_MNTENT_H))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000175 /*
176 * If the root is mounted read-only, then /etc/mtab is
177 * probably not correct; so we won't issue a warning based on
178 * it.
179 */
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000180 fd = open(MOUNTED, O_RDWR);
181 if (fd < 0) {
182 if (errno == EROFS)
183 return;
184 } else
185 close(fd);
186#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000187
188 if (!rwflag) {
189 printf("Warning! %s is mounted.\n", device_name);
190 return;
191 }
192
193 printf ("%s is mounted. ", device_name);
194 if (isatty (0) && isatty (1))
195 cont = ask_yn("Do you really want to continue", -1);
196 else
197 cont = 0;
198 if (!cont) {
199 printf ("check aborted.\n");
200 exit (0);
201 }
202 return;
203}
204
205static void sync_disks(NOARGS)
206{
207 sync();
208 sync();
209 sleep(1);
210 sync();
211}
212
Theodore Ts'of3db3561997-04-26 13:34:30 +0000213#define MIN_CHECK 1
214#define MAX_CHECK 2
215
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000216static const char *corrupt_msg =
217"\nThe superblock could not be read or does not describe a correct ext2\n"
218"filesystem. If the device is valid and it really contains an ext2\n"
219"filesystem (and not swap or ufs or something else), then the superblock\n"
220"is corrupt, and you might try running e2fsck with an alternate superblock:\n"
221" e2fsck -b 8193 <device>\n\n";
Theodore Ts'of3db3561997-04-26 13:34:30 +0000222
223static void check_super_value(const char *descr, unsigned long value,
224 int flags, unsigned long min, unsigned long max)
225{
226 if (((flags & MIN_CHECK) && (value < min)) ||
227 ((flags & MAX_CHECK) && (value > max))) {
228 printf("Corruption found in superblock. (%s = %lu).\n",
229 descr, value);
230 printf(corrupt_msg);
231 fatal_error(0);
232 }
233}
234
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000235static void relocate_hint(void)
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000236{
237 static hint_issued = 0;
238
239 /* Only issue the hint once */
240 if (hint_issued)
241 return;
242
243 printf("Note: if there is several inode or block bitmap blocks\n"
244 "which require relocation, or one part of the inode table\n"
245 "which must be moved, you may wish to try running e2fsck\n"
246 "the '-b 8193' option first. The problem may lie only with\n"
247 "the primary block group descriptor, and the backup block\n"
248 "group descriptor may be OK.\n\n");
249 hint_issued = 1;
250}
251
252
Theodore Ts'o3839e651997-04-26 13:21:57 +0000253static void check_super_block(ext2_filsys fs)
254{
255 blk_t first_block, last_block;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000256 struct ext2fs_sb *s = (struct ext2fs_sb *) fs->super;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000257 blk_t blocks_per_group = fs->super->s_blocks_per_group;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000258 int i;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000259 blk_t should_be;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000260 errcode_t retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000261
Theodore Ts'of3db3561997-04-26 13:34:30 +0000262 /*
263 * Verify the super block constants...
264 */
265 check_super_value("inodes_count", s->s_inodes_count,
266 MIN_CHECK, 1, 0);
267 check_super_value("blocks_count", s->s_blocks_count,
268 MIN_CHECK, 1, 0);
269 check_super_value("first_data_block", s->s_first_data_block,
270 MAX_CHECK, 0, s->s_blocks_count);
271 check_super_value("log_frag_size", s->s_log_frag_size,
272 MAX_CHECK, 0, 2);
273 check_super_value("log_block_size", s->s_log_block_size,
274 MIN_CHECK | MAX_CHECK, s->s_log_frag_size,
275 2);
276 check_super_value("frags_per_group", s->s_frags_per_group,
277 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
278 check_super_value("blocks_per_group", s->s_blocks_per_group,
279 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
280 check_super_value("inodes_per_group", s->s_inodes_per_group,
281 MIN_CHECK, 1, 0);
282 check_super_value("r_blocks_count", s->s_r_blocks_count,
283 MAX_CHECK, 0, s->s_blocks_count);
284
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000285 retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s),
286 &should_be);
287 if (retval) {
288 com_err("ext2fs_get_device_size", retval,
289 "while trying to check physical size of filesystem");
290 fatal_error(0);
291 }
292 if (should_be < s->s_blocks_count) {
293 printf("The filesystem size (according to the superblock) is %d blocks\n", s->s_blocks_count);
294 printf("The physical size of the device is %d blocks\n",
295 should_be);
296 printf("Either the superblock or the partition table is likely to be corrupt!\n");
297 preenhalt(fs);
298 if (ask("Abort", 1))
299 fatal_error(0);
300 }
301
Theodore Ts'of3db3561997-04-26 13:34:30 +0000302 if (s->s_log_block_size != s->s_log_frag_size) {
303 printf("Superblock block_size = %d, fragsize = %d.\n",
304 EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s));
305 printf("This version of e2fsck does not support fragment "
306 "sizes different\n"
307 "from the block size.\n");
308 fatal_error(0);
309 }
310
311 should_be = s->s_frags_per_group /
312 (s->s_log_block_size - s->s_log_frag_size + 1);
313 if (s->s_blocks_per_group != should_be) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000314 printf("Superblock blocks_per_group = %u, should "
315 "have been %u\n", s->s_blocks_per_group,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000316 should_be);
317 printf(corrupt_msg);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000318 fatal_error(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000319 }
320
321 should_be = (s->s_log_block_size == 0) ? 1 : 0;
322 if (s->s_first_data_block != should_be) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000323 printf("Superblock first_data_block = %u, should "
324 "have been %u\n", s->s_first_data_block,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000325 should_be);
326 printf(corrupt_msg);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000327 fatal_error(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000328 }
329
330 /*
331 * Verify the group descriptors....
332 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000333 first_block = fs->super->s_first_data_block;
334 last_block = first_block + blocks_per_group;
335
336 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000337 if (i == fs->group_desc_count - 1)
338 last_block = fs->super->s_blocks_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000339 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
340 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000341 relocate_hint();
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000342 printf("Block bitmap for group %d is not in group. "
343 "(block %u)\n",
344 i, fs->group_desc[i].bg_block_bitmap);
345 preenhalt(fs);
346 if (!ask("Relocate", 1)) {
347 fatal_error("Block bitmap not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000348 }
349 fs->group_desc[i].bg_block_bitmap = 0;
350 invalid_block_bitmap[i]++;
351 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000352 }
353 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
354 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000355 relocate_hint();
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000356 printf("Inode bitmap group %d not in group. "
357 "(block %u)\n",
358 i, fs->group_desc[i].bg_inode_bitmap);
359 preenhalt(fs);
360 if (!ask("Relocate", 1)) {
361 fatal_error("Inode bitmap not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000362 }
363 fs->group_desc[i].bg_inode_bitmap = 0;
364 invalid_inode_bitmap[i]++;
365 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000366 }
367 if ((fs->group_desc[i].bg_inode_table < first_block) ||
368 ((fs->group_desc[i].bg_inode_table +
369 fs->inode_blocks_per_group - 1) >= last_block)) {
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000370 relocate_hint();
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000371 printf("Inode table for group %d not in group. "
372 "(block %u)\n",
373 i, fs->group_desc[i].bg_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000374 printf("WARNING: SEVERE DATA LOSS POSSIBLE.\n");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000375 preenhalt(fs);
376 if (!ask("Relocate", 1)) {
377 fatal_error("Inode table not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000378 }
379 fs->group_desc[i].bg_inode_table = 0;
380 invalid_inode_table[i]++;
381 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000382 }
383 first_block += fs->super->s_blocks_per_group;
384 last_block += fs->super->s_blocks_per_group;
385 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000386
387 /*
388 * If the UUID field isn't assigned, assign it.
389 */
390 if (rwflag && uuid_is_null(s->s_uuid)) {
391 if (preen)
392 printf("%s: Adding UUID to filesystem.\n",
393 device_name);
394 else
395 printf("Filesystem did not have a UUID; "
396 "generating one.\n\n");
397 uuid_generate(s->s_uuid);
398 ext2fs_mark_super_dirty(fs);
399 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000400 return;
401}
402
403/*
404 * This routine checks to see if a filesystem can be skipped; if so,
405 * it will exit with E2FSCK_OK. Under some conditions it will print a
406 * message explaining why a check is being forced.
407 */
408static void check_if_skip(ext2_filsys fs)
409{
410 const char *reason = NULL;
411
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000412 if (force || bad_blocks_file || cflag || swapfs)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000413 return;
414
415 if (fs->super->s_state & EXT2_ERROR_FS)
416 reason = "contains a file system with errors";
417 else if (fs->super->s_mnt_count >=
418 (unsigned) fs->super->s_max_mnt_count)
419 reason = "has reached maximal mount count";
420 else if (fs->super->s_checkinterval &&
421 time(0) >= (fs->super->s_lastcheck +
422 fs->super->s_checkinterval))
423 reason = "has gone too long without being checked";
Theodore Ts'o5c576471997-04-29 15:29:49 +0000424 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
425 reason = "was not cleanly unmounted";
Theodore Ts'o3839e651997-04-26 13:21:57 +0000426 if (reason) {
427 printf("%s %s, check forced.\n", device_name, reason);
428 return;
429 }
Theodore Ts'o5c576471997-04-29 15:29:49 +0000430 printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name,
431 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
432 fs->super->s_inodes_count,
433 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
434 fs->super->s_blocks_count);
435 ext2fs_close(fs);
436 exit(FSCK_OK);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000437}
438
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000439#define PATH_SET "PATH=/sbin"
440
Theodore Ts'o3839e651997-04-26 13:21:57 +0000441static void PRS(int argc, char *argv[])
442{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000443 int flush = 0;
444 char c;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000445#ifdef MTRACE
Theodore Ts'of3db3561997-04-26 13:34:30 +0000446 extern void *mallwatch;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000447#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000448 char *oldpath = getenv("PATH");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000449
450 /* Update our PATH to include /sbin */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000451 if (oldpath) {
452 char *newpath;
453
454 newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
455 if (!newpath)
456 fatal_error("Couldn't malloc() newpath");
457 strcpy (newpath, PATH_SET);
458 strcat (newpath, ":");
459 strcat (newpath, oldpath);
460 putenv (newpath);
461 } else
462 putenv (PATH_SET);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000463
464 setbuf(stdout, NULL);
465 setbuf(stderr, NULL);
466 initialize_ext2_error_table();
467
468 if (argc && *argv)
469 program_name = *argv;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000470 while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000471 switch (c) {
472 case 'p':
473 case 'a':
474 preen = 1;
475 yflag = nflag = 0;
476 break;
477 case 'n':
478 nflag = 1;
479 preen = yflag = 0;
480 break;
481 case 'y':
482 yflag = 1;
483 preen = nflag = 0;
484 break;
485 case 't':
486 tflag++;
487 break;
488 case 'c':
489 cflag++;
490 break;
491 case 'r':
492 /* What we do by default, anyway! */
493 break;
494 case 'b':
495 superblock = atoi(optarg);
496 break;
497 case 'B':
498 blocksize = atoi(optarg);
499 break;
500 case 'I':
501 inode_buffer_blocks = atoi(optarg);
502 break;
503 case 'P':
504 process_inode_size = atoi(optarg);
505 break;
506 case 'L':
507 replace_bad_blocks++;
508 case 'l':
509 bad_blocks_file = malloc(strlen(optarg)+1);
510 if (!bad_blocks_file)
511 fatal_error("Couldn't malloc bad_blocks_file");
512 strcpy(bad_blocks_file, optarg);
513 break;
514 case 'd':
515 debug = 1;
516 break;
517 case 'f':
518 force = 1;
519 break;
520 case 'F':
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000521#ifdef BLKFLSBUF
Theodore Ts'o3839e651997-04-26 13:21:57 +0000522 flush = 1;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000523#else
524 fatal_error ("-F not supported");
525#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000526 break;
527 case 'v':
528 verbose = 1;
529 break;
530 case 'V':
531 show_version_only = 1;
532 break;
533#ifdef MTRACE
534 case 'M':
535 mallwatch = (void *) strtol(optarg, NULL, 0);
536 break;
537#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000538 case 'N':
539 device_name = optarg;
540 break;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000541 case 's':
542 normalize_swapfs = 1;
543 case 'S':
544 swapfs = 1;
545 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000546 default:
547 usage ();
548 }
549 if (show_version_only)
550 return;
551 if (optind != argc - 1)
552 usage ();
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000553 if (nflag && !bad_blocks_file && !cflag && !swapfs)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000554 rwflag = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000555 filesystem_name = argv[optind];
556 if (device_name == 0)
557 device_name = filesystem_name;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000558 if (flush) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000559#ifdef BLKFLSBUF
560 int fd = open(filesystem_name, O_RDONLY, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000561
562 if (fd < 0) {
563 com_err("open", errno, "while opening %s for flushing",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000564 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000565 exit(FSCK_ERROR);
566 }
567 if (ioctl(fd, BLKFLSBUF, 0) < 0) {
568 com_err("BLKFLSBUF", errno, "while trying to flush %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000569 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000570 exit(FSCK_ERROR);
571 }
572 close(fd);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000573#else
574 fatal_error ("BLKFLSBUF not supported");
575#endif /* BLKFLSBUF */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000576 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000577 if (swapfs) {
578 if (cflag || bad_blocks_file) {
579 fprintf(stderr, "Incompatible options not "
580 "allowed when byte-swapping.\n");
581 fatal_error(0);
582 }
583 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000584}
585
586int main (int argc, char *argv[])
587{
588 errcode_t retval = 0;
589 int exit_value = FSCK_OK;
590 int i;
591 ext2_filsys fs;
592
593#ifdef MTRACE
594 mtrace();
595#endif
596#ifdef MCHECK
597 mcheck(0);
598#endif
599
600 init_resource_track(&global_rtrack);
601
602 PRS(argc, argv);
603
604 if (!preen)
605 fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
606 E2FSPROGS_VERSION, E2FSPROGS_DATE,
607 EXT2FS_VERSION, EXT2FS_DATE);
608
Theodore Ts'o5c576471997-04-29 15:29:49 +0000609 if (show_version_only) {
610 fprintf(stderr, "\tUsing %s\n",
611 error_message(EXT2_ET_BASE));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000612 exit(0);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000613 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000614
615 check_mount();
616
617 if (!preen && !nflag && !yflag) {
618 if (!isatty (0) || !isatty (1))
619 die ("need terminal for interactive repairs");
620 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000621restart:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000622 sync_disks();
623 if (superblock && blocksize) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000624 retval = ext2fs_open(filesystem_name,
625 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000626 superblock, blocksize, unix_io_manager,
627 &fs);
628 } else if (superblock) {
629 for (i=0; possible_block_sizes[i]; i++) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000630 retval = ext2fs_open(filesystem_name,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000631 rwflag ? EXT2_FLAG_RW : 0,
632 superblock,
633 possible_block_sizes[i],
634 unix_io_manager, &fs);
635 if (!retval)
636 break;
637 }
638 } else
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000639 retval = ext2fs_open(filesystem_name,
640 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000641 0, 0, unix_io_manager, &fs);
642 if (retval) {
643 com_err(program_name, retval, "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000644 filesystem_name);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000645 if (retval == EXT2_ET_REV_TOO_HIGH)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000646 printf ("Get a newer version of e2fsck!\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000647 else if (retval == EXT2_ET_SHORT_READ)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000648 printf ("Could this be a zero-length partition?\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000649 else if ((retval == EPERM) || (retval == EACCES))
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000650 printf("You must have %s access to the "
651 "filesystem or be root\n",
652 rwflag ? "r/w" : "r/o");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000653 else if (retval == ENXIO)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000654 printf("Possibly non-existent or swap device?\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000655 else
Theodore Ts'of3db3561997-04-26 13:34:30 +0000656 printf(corrupt_msg);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000657 fatal_error(0);
658 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000659
660#ifdef EXT2_CURRENT_REV
661 if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000662 com_err(program_name, EXT2_ET_REV_TOO_HIGH,
663 "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000664 filesystem_name);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000665 printf ("Get a newer version of e2fsck!\n");
666 fatal_error(0);
667 }
668#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000669 /*
670 * If the user specified a specific superblock, presumably the
671 * master superblock has been trashed. So we mark the
672 * superblock as dirty, so it can be written out.
673 */
674 if (superblock && rwflag)
675 ext2fs_mark_super_dirty(fs);
676
Theodore Ts'o5c576471997-04-29 15:29:49 +0000677 /*
678 * Don't overwrite the backup superblock and block
679 * descriptors, until we're sure the filesystem is OK....
680 */
681 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
682
Theodore Ts'o3839e651997-04-26 13:21:57 +0000683 ehandler_init(fs->io);
684
Theodore Ts'of3db3561997-04-26 13:34:30 +0000685 invalid_inode_bitmap = allocate_memory(sizeof(int) *
686 fs->group_desc_count,
687 "invalid_inode_bitmap");
688 invalid_block_bitmap = allocate_memory(sizeof(int) *
689 fs->group_desc_count,
690 "invalid_block_bitmap");
691 invalid_inode_table = allocate_memory(sizeof(int) *
692 fs->group_desc_count,
693 "invalid_inode_table");
694
Theodore Ts'o3839e651997-04-26 13:21:57 +0000695 check_super_block(fs);
696 check_if_skip(fs);
697 if (bad_blocks_file)
698 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
699 else if (cflag)
700 test_disk(fs);
701
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000702 if (normalize_swapfs) {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000703 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ==
704 ext2fs_native_flag()) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000705 fprintf(stderr, "%s: Filesystem byte order "
706 "already normalized.\n", device_name);
707 fatal_error(0);
708 }
709 }
710 if (swapfs)
711 swap_filesys(fs);
712
Theodore Ts'o3839e651997-04-26 13:21:57 +0000713 /*
714 * Mark the system as valid, 'til proven otherwise
715 */
716 ext2fs_mark_valid(fs);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000717
Theodore Ts'o3839e651997-04-26 13:21:57 +0000718 pass1(fs);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000719 free(invalid_inode_bitmap);
720 free(invalid_block_bitmap);
721 free(invalid_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000722 if (restart_e2fsck) {
723 ext2fs_close(fs);
724 printf("Restarting e2fsck from the beginning...\n");
725 restart_e2fsck = 0;
726 goto restart;
727 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000728 pass2(fs);
729 pass3(fs);
730 pass4(fs);
731 pass5(fs);
732
733#ifdef MTRACE
734 mtrace_print("Cleanup");
735#endif
736 if (ext2fs_test_changed(fs)) {
737 exit_value = FSCK_NONDESTRUCT;
738 if (!preen)
739 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
740 device_name);
741 if (root_filesystem && !read_only_root) {
742 printf("%s: ***** REBOOT LINUX *****\n", device_name);
743 exit_value = FSCK_REBOOT;
744 }
745 }
Theodore Ts'o5c576471997-04-29 15:29:49 +0000746 if (ext2fs_test_valid(fs))
747 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
748 else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000749 exit_value = FSCK_UNCORRECTED;
750 if (rwflag) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000751 if (ext2fs_test_valid(fs)) {
752 if (!(fs->super->s_state & EXT2_VALID_FS))
753 exit_value = FSCK_NONDESTRUCT;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000754 fs->super->s_state = EXT2_VALID_FS;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000755 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000756 fs->super->s_state &= ~EXT2_VALID_FS;
757 fs->super->s_mnt_count = 0;
758 fs->super->s_lastcheck = time(NULL);
759 ext2fs_mark_super_dirty(fs);
760 }
761 show_stats(fs);
762
763 write_bitmaps(fs);
764 ext2fs_close(fs);
765 sync_disks();
766
767 if (tflag)
768 print_resource_track(&global_rtrack);
769
770 return exit_value;
771}