blob: 9048298471547595b95970ae289c9b6e9a697de7 [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";
424 if (reason) {
425 printf("%s %s, check forced.\n", device_name, reason);
426 return;
427 }
428 if (fs->super->s_state & EXT2_VALID_FS) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000429 printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name,
430 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
431 fs->super->s_inodes_count,
432 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
433 fs->super->s_blocks_count);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000434 ext2fs_close(fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000435 exit(FSCK_OK);
436 }
437}
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
609 if (show_version_only)
610 exit(0);
611
612 check_mount();
613
614 if (!preen && !nflag && !yflag) {
615 if (!isatty (0) || !isatty (1))
616 die ("need terminal for interactive repairs");
617 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000618restart:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000619 sync_disks();
620 if (superblock && blocksize) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000621 retval = ext2fs_open(filesystem_name,
622 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000623 superblock, blocksize, unix_io_manager,
624 &fs);
625 } else if (superblock) {
626 for (i=0; possible_block_sizes[i]; i++) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000627 retval = ext2fs_open(filesystem_name,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000628 rwflag ? EXT2_FLAG_RW : 0,
629 superblock,
630 possible_block_sizes[i],
631 unix_io_manager, &fs);
632 if (!retval)
633 break;
634 }
635 } else
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000636 retval = ext2fs_open(filesystem_name,
637 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000638 0, 0, unix_io_manager, &fs);
639 if (retval) {
640 com_err(program_name, retval, "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000641 filesystem_name);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000642 if (retval == EXT2_ET_REV_TOO_HIGH)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000643 printf ("Get a newer version of e2fsck!\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000644 else if (retval == EXT2_ET_SHORT_READ)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000645 printf ("Could this be a zero-length partition?\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000646 else if ((retval == EPERM) || (retval == EACCES))
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000647 printf("You must have %s access to the "
648 "filesystem or be root\n",
649 rwflag ? "r/w" : "r/o");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000650 else if (retval == ENXIO)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000651 printf("Possibly non-existent or swap device?\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000652 else
Theodore Ts'of3db3561997-04-26 13:34:30 +0000653 printf(corrupt_msg);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000654 fatal_error(0);
655 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000656
657#ifdef EXT2_CURRENT_REV
658 if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000659 com_err(program_name, EXT2_ET_REV_TOO_HIGH,
660 "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000661 filesystem_name);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000662 printf ("Get a newer version of e2fsck!\n");
663 fatal_error(0);
664 }
665#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000666 /*
667 * If the user specified a specific superblock, presumably the
668 * master superblock has been trashed. So we mark the
669 * superblock as dirty, so it can be written out.
670 */
671 if (superblock && rwflag)
672 ext2fs_mark_super_dirty(fs);
673
674 ehandler_init(fs->io);
675
Theodore Ts'of3db3561997-04-26 13:34:30 +0000676 invalid_inode_bitmap = allocate_memory(sizeof(int) *
677 fs->group_desc_count,
678 "invalid_inode_bitmap");
679 invalid_block_bitmap = allocate_memory(sizeof(int) *
680 fs->group_desc_count,
681 "invalid_block_bitmap");
682 invalid_inode_table = allocate_memory(sizeof(int) *
683 fs->group_desc_count,
684 "invalid_inode_table");
685
Theodore Ts'o3839e651997-04-26 13:21:57 +0000686 check_super_block(fs);
687 check_if_skip(fs);
688 if (bad_blocks_file)
689 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
690 else if (cflag)
691 test_disk(fs);
692
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000693 if (normalize_swapfs) {
694 if ((fs->flags & EXT2_SWAP_BYTES) == ext2fs_native_flag()) {
695 fprintf(stderr, "%s: Filesystem byte order "
696 "already normalized.\n", device_name);
697 fatal_error(0);
698 }
699 }
700 if (swapfs)
701 swap_filesys(fs);
702
Theodore Ts'o3839e651997-04-26 13:21:57 +0000703 /*
704 * Mark the system as valid, 'til proven otherwise
705 */
706 ext2fs_mark_valid(fs);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000707
Theodore Ts'o3839e651997-04-26 13:21:57 +0000708 pass1(fs);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000709 free(invalid_inode_bitmap);
710 free(invalid_block_bitmap);
711 free(invalid_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000712 if (restart_e2fsck) {
713 ext2fs_close(fs);
714 printf("Restarting e2fsck from the beginning...\n");
715 restart_e2fsck = 0;
716 goto restart;
717 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000718 pass2(fs);
719 pass3(fs);
720 pass4(fs);
721 pass5(fs);
722
723#ifdef MTRACE
724 mtrace_print("Cleanup");
725#endif
726 if (ext2fs_test_changed(fs)) {
727 exit_value = FSCK_NONDESTRUCT;
728 if (!preen)
729 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
730 device_name);
731 if (root_filesystem && !read_only_root) {
732 printf("%s: ***** REBOOT LINUX *****\n", device_name);
733 exit_value = FSCK_REBOOT;
734 }
735 }
736 if (!ext2fs_test_valid(fs))
737 exit_value = FSCK_UNCORRECTED;
738 if (rwflag) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000739 if (ext2fs_test_valid(fs)) {
740 if (!(fs->super->s_state & EXT2_VALID_FS))
741 exit_value = FSCK_NONDESTRUCT;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000742 fs->super->s_state = EXT2_VALID_FS;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000743 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000744 fs->super->s_state &= ~EXT2_VALID_FS;
745 fs->super->s_mnt_count = 0;
746 fs->super->s_lastcheck = time(NULL);
747 ext2fs_mark_super_dirty(fs);
748 }
749 show_stats(fs);
750
751 write_bitmaps(fs);
752 ext2fs_close(fs);
753 sync_disks();
754
755 if (tflag)
756 print_resource_track(&global_rtrack);
757
758 return exit_value;
759}