blob: 9cebae4f8f98014c54f603f7bcc8a052d1b20296 [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 *
Theodore Ts'o21c84b71997-04-29 16:15:03 +00004 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
Theodore Ts'o3839e651997-04-26 13:21:57 +000010 */
11
12/* Usage: e2fsck [-dfpnsvy] device
13 * -d -- debugging this program
14 * -f -- check the fs even if it is marked valid
15 * -p -- "preen" the filesystem
16 * -n -- open the filesystem r/o mode; never try to fix problems
17 * -v -- verbose (tells how many files)
18 * -y -- always answer yes to questions
19 *
20 * The device may be a block device or a image of one, but this isn't
21 * enforced (but it's not much fun on a character device :-).
22 */
23
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000024#include <stdio.h>
25#ifdef HAVE_STDLIB_H
26#include <stdlib.h>
27#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000028#include <string.h>
29#include <fcntl.h>
30#include <ctype.h>
31#include <termios.h>
32#include <time.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000033#ifdef HAVE_GETOPT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000034#include <getopt.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000035#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000036#include <unistd.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000037#ifdef HAVE_ERRNO_H
38#include <errno.h>
39#endif
40#ifdef HAVE_MNTENT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000041#include <mntent.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000042#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000043#include <sys/ioctl.h>
44#include <malloc.h>
45
46#include "et/com_err.h"
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000047#include "uuid/uuid.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000048#include "e2fsck.h"
Theodore Ts'o21c84b71997-04-29 16:15:03 +000049#include "problem.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000050#include "../version.h"
51
52extern int isatty(int);
53
54const char * program_name = "e2fsck";
55const char * device_name = NULL;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000056const char * filesystem_name = NULL;
Theodore Ts'o3839e651997-04-26 13:21:57 +000057
58/* Command line options */
59int nflag = 0;
60int yflag = 0;
61int tflag = 0; /* Do timing */
62int cflag = 0; /* check disk */
63int preen = 0;
64int rwflag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000065int swapfs = 0;
66int normalize_swapfs = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +000067int inode_buffer_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000068blk_t use_superblock;
Theodore Ts'o3839e651997-04-26 13:21:57 +000069blk_t superblock;
70int blocksize = 0;
71int verbose = 0;
72int list = 0;
73int debug = 0;
74int force = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +000075int invalid_bitmaps = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +000076static int show_version_only = 0;
77
78static int replace_bad_blocks = 0;
79static char *bad_blocks_file = 0;
80
81static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
82
83struct resource_track global_rtrack;
84
85static int root_filesystem = 0;
86static int read_only_root = 0;
87
Theodore Ts'of3db3561997-04-26 13:34:30 +000088int *invalid_inode_bitmap;
89int *invalid_block_bitmap;
90int *invalid_inode_table;
91int restart_e2fsck = 0;
92
Theodore Ts'o3839e651997-04-26 13:21:57 +000093static void usage(NOARGS)
94{
95 fprintf(stderr,
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000096 "Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n"
Theodore Ts'of3db3561997-04-26 13:34:30 +000097 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
98 "\t\t[-l|-L bad_blocks_file] device\n", program_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +000099 exit(FSCK_USAGE);
100}
101
102static void show_stats(ext2_filsys fs)
103{
104 int inodes, inodes_used, blocks, blocks_used;
105 int dir_links;
106 int num_files, num_links;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000107 int frag_percent;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000108
109 dir_links = 2 * fs_directory_count - 1;
110 num_files = fs_total_count - dir_links;
111 num_links = fs_links_count - dir_links;
112 inodes = fs->super->s_inodes_count;
113 inodes_used = (fs->super->s_inodes_count -
114 fs->super->s_free_inodes_count);
115 blocks = fs->super->s_blocks_count;
116 blocks_used = (fs->super->s_blocks_count -
117 fs->super->s_free_blocks_count);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000118
119 frag_percent = (10000 * fs_fragmented) / inodes_used;
120 frag_percent = (frag_percent + 5) / 10;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000121
122 if (!verbose) {
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000123 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
Theodore Ts'o74becf31997-04-26 14:37:06 +0000124 device_name, inodes_used, inodes,
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000125 frag_percent / 10, frag_percent % 10,
Theodore Ts'o74becf31997-04-26 14:37:06 +0000126 blocks_used, blocks);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000127 return;
128 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000129 printf ("\n%8d inode%s used (%d%%)\n", inodes_used,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000130 (inodes_used != 1) ? "s" : "",
131 100 * inodes_used / inodes);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000132 printf ("%8d non-contiguous inodes (%0d.%d%%)\n",
133 fs_fragmented, frag_percent / 10, frag_percent % 10);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000134 printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n",
135 fs_ind_count, fs_dind_count, fs_tind_count);
136 printf ("%8d block%s used (%d%%)\n"
137 "%8d bad block%s\n", blocks_used,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000138 (blocks_used != 1) ? "s" : "",
139 100 * blocks_used / blocks, fs_badblocks_count,
140 fs_badblocks_count != 1 ? "s" : "");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000141 printf ("\n%8d regular file%s\n"
142 "%8d director%s\n"
143 "%8d character device file%s\n"
144 "%8d block device file%s\n"
145 "%8d fifo%s\n"
146 "%8d link%s\n"
147 "%8d symbolic link%s (%d fast symbolic link%s)\n"
148 "%8d socket%s\n"
149 "--------\n"
150 "%8d file%s\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000151 fs_regular_count, (fs_regular_count != 1) ? "s" : "",
152 fs_directory_count, (fs_directory_count != 1) ? "ies" : "y",
153 fs_chardev_count, (fs_chardev_count != 1) ? "s" : "",
154 fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "",
155 fs_fifo_count, (fs_fifo_count != 1) ? "s" : "",
156 fs_links_count - dir_links,
157 ((fs_links_count - dir_links) != 1) ? "s" : "",
158 fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "",
159 fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "",
160 fs_sockets_count, (fs_sockets_count != 1) ? "s" : "",
161 fs_total_count - dir_links,
162 ((fs_total_count - dir_links) != 1) ? "s" : "");
163}
164
165static void check_mount(NOARGS)
166{
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000167 errcode_t retval;
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000168 int mount_flags, cont, fd;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000169
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000170 retval = ext2fs_check_if_mounted(filesystem_name, &mount_flags);
171 if (retval) {
172 com_err("ext2fs_check_if_mount", retval,
173 "while determining whether %s is mounted.",
174 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000175 return;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000176 }
177 if (!(mount_flags & EXT2_MF_MOUNTED))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000178 return;
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000179
Theodore Ts'o74becf31997-04-26 14:37:06 +0000180#if (defined(__linux__) && defined(HAVE_MNTENT_H))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000181 /*
182 * If the root is mounted read-only, then /etc/mtab is
183 * probably not correct; so we won't issue a warning based on
184 * it.
185 */
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000186 fd = open(MOUNTED, O_RDWR);
187 if (fd < 0) {
188 if (errno == EROFS)
189 return;
190 } else
191 close(fd);
192#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000193
194 if (!rwflag) {
195 printf("Warning! %s is mounted.\n", device_name);
196 return;
197 }
198
199 printf ("%s is mounted. ", device_name);
200 if (isatty (0) && isatty (1))
201 cont = ask_yn("Do you really want to continue", -1);
202 else
203 cont = 0;
204 if (!cont) {
205 printf ("check aborted.\n");
206 exit (0);
207 }
208 return;
209}
210
211static void sync_disks(NOARGS)
212{
213 sync();
214 sync();
215 sleep(1);
216 sync();
217}
218
Theodore Ts'of3db3561997-04-26 13:34:30 +0000219#define MIN_CHECK 1
220#define MAX_CHECK 2
221
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000222static const char *corrupt_msg =
223"\nThe superblock could not be read or does not describe a correct ext2\n"
224"filesystem. If the device is valid and it really contains an ext2\n"
225"filesystem (and not swap or ufs or something else), then the superblock\n"
226"is corrupt, and you might try running e2fsck with an alternate superblock:\n"
227" e2fsck -b 8193 <device>\n\n";
Theodore Ts'of3db3561997-04-26 13:34:30 +0000228
229static void check_super_value(const char *descr, unsigned long value,
230 int flags, unsigned long min, unsigned long max)
231{
232 if (((flags & MIN_CHECK) && (value < min)) ||
233 ((flags & MAX_CHECK) && (value > max))) {
234 printf("Corruption found in superblock. (%s = %lu).\n",
235 descr, value);
236 printf(corrupt_msg);
237 fatal_error(0);
238 }
239}
240
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000241static void relocate_hint(void)
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000242{
243 static hint_issued = 0;
244
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000245 /*
246 * Only issue the hint once, and only if we're using the
247 * primary superblocks.
248 */
249 if (hint_issued || superblock)
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000250 return;
251
252 printf("Note: if there is several inode or block bitmap blocks\n"
253 "which require relocation, or one part of the inode table\n"
254 "which must be moved, you may wish to try running e2fsck\n"
255 "the '-b 8193' option first. The problem may lie only with\n"
256 "the primary block group descriptor, and the backup block\n"
257 "group descriptor may be OK.\n\n");
258 hint_issued = 1;
259}
260
261
Theodore Ts'o3839e651997-04-26 13:21:57 +0000262static void check_super_block(ext2_filsys fs)
263{
264 blk_t first_block, last_block;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000265 struct ext2fs_sb *s = (struct ext2fs_sb *) fs->super;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000266 blk_t blocks_per_group = fs->super->s_blocks_per_group;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000267 int i;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000268 blk_t should_be;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000269 errcode_t retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000270 struct problem_context pctx;
271
272 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000273
Theodore Ts'of3db3561997-04-26 13:34:30 +0000274 /*
275 * Verify the super block constants...
276 */
277 check_super_value("inodes_count", s->s_inodes_count,
278 MIN_CHECK, 1, 0);
279 check_super_value("blocks_count", s->s_blocks_count,
280 MIN_CHECK, 1, 0);
281 check_super_value("first_data_block", s->s_first_data_block,
282 MAX_CHECK, 0, s->s_blocks_count);
283 check_super_value("log_frag_size", s->s_log_frag_size,
284 MAX_CHECK, 0, 2);
285 check_super_value("log_block_size", s->s_log_block_size,
286 MIN_CHECK | MAX_CHECK, s->s_log_frag_size,
287 2);
288 check_super_value("frags_per_group", s->s_frags_per_group,
289 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
290 check_super_value("blocks_per_group", s->s_blocks_per_group,
291 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
292 check_super_value("inodes_per_group", s->s_inodes_per_group,
293 MIN_CHECK, 1, 0);
294 check_super_value("r_blocks_count", s->s_r_blocks_count,
295 MAX_CHECK, 0, s->s_blocks_count);
296
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000297 retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s),
298 &should_be);
299 if (retval) {
300 com_err("ext2fs_get_device_size", retval,
301 "while trying to check physical size of filesystem");
302 fatal_error(0);
303 }
304 if (should_be < s->s_blocks_count) {
305 printf("The filesystem size (according to the superblock) is %d blocks\n", s->s_blocks_count);
306 printf("The physical size of the device is %d blocks\n",
307 should_be);
308 printf("Either the superblock or the partition table is likely to be corrupt!\n");
309 preenhalt(fs);
310 if (ask("Abort", 1))
311 fatal_error(0);
312 }
313
Theodore Ts'of3db3561997-04-26 13:34:30 +0000314 if (s->s_log_block_size != s->s_log_frag_size) {
315 printf("Superblock block_size = %d, fragsize = %d.\n",
316 EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s));
317 printf("This version of e2fsck does not support fragment "
318 "sizes different\n"
319 "from the block size.\n");
320 fatal_error(0);
321 }
322
323 should_be = s->s_frags_per_group /
324 (s->s_log_block_size - s->s_log_frag_size + 1);
325 if (s->s_blocks_per_group != should_be) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000326 printf("Superblock blocks_per_group = %u, should "
327 "have been %u\n", s->s_blocks_per_group,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000328 should_be);
329 printf(corrupt_msg);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000330 fatal_error(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000331 }
332
333 should_be = (s->s_log_block_size == 0) ? 1 : 0;
334 if (s->s_first_data_block != should_be) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000335 printf("Superblock first_data_block = %u, should "
336 "have been %u\n", s->s_first_data_block,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000337 should_be);
338 printf(corrupt_msg);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000339 fatal_error(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000340 }
341
342 /*
343 * Verify the group descriptors....
344 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000345 first_block = fs->super->s_first_data_block;
346 last_block = first_block + blocks_per_group;
347
348 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000349 pctx.group = i;
350
Theodore Ts'of3db3561997-04-26 13:34:30 +0000351 if (i == fs->group_desc_count - 1)
352 last_block = fs->super->s_blocks_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000353 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
354 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000355 relocate_hint();
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000356 pctx.blk = fs->group_desc[i].bg_block_bitmap;
357 if (fix_problem(fs, PR_0_BB_NOT_GROUP, &pctx)) {
358 fs->group_desc[i].bg_block_bitmap = 0;
359 invalid_block_bitmap[i]++;
360 invalid_bitmaps++;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000361 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000362 }
363 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
364 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000365 relocate_hint();
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000366 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
367 if (fix_problem(fs, PR_0_IB_NOT_GROUP, &pctx)) {
368 fs->group_desc[i].bg_inode_bitmap = 0;
369 invalid_inode_bitmap[i]++;
370 invalid_bitmaps++;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000371 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000372 }
373 if ((fs->group_desc[i].bg_inode_table < first_block) ||
374 ((fs->group_desc[i].bg_inode_table +
375 fs->inode_blocks_per_group - 1) >= last_block)) {
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000376 relocate_hint();
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000377 pctx.blk = fs->group_desc[i].bg_inode_table;
378 if (fix_problem(fs, PR_0_ITABLE_NOT_GROUP, &pctx)) {
379 fs->group_desc[i].bg_inode_table = 0;
380 invalid_inode_table[i]++;
381 invalid_bitmaps++;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000382 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000383 }
384 first_block += fs->super->s_blocks_per_group;
385 last_block += fs->super->s_blocks_per_group;
386 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000387 /*
388 * If we have invalid bitmaps, set the error state of the
389 * filesystem.
390 */
391 if (invalid_bitmaps && rwflag) {
392 fs->super->s_state &= ~EXT2_VALID_FS;
393 ext2fs_mark_super_dirty(fs);
394 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000395
396 /*
397 * If the UUID field isn't assigned, assign it.
398 */
399 if (rwflag && uuid_is_null(s->s_uuid)) {
400 if (preen)
401 printf("%s: Adding UUID to filesystem.\n",
402 device_name);
403 else
404 printf("Filesystem did not have a UUID; "
405 "generating one.\n\n");
406 uuid_generate(s->s_uuid);
407 ext2fs_mark_super_dirty(fs);
408 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000409 return;
410}
411
412/*
413 * This routine checks to see if a filesystem can be skipped; if so,
414 * it will exit with E2FSCK_OK. Under some conditions it will print a
415 * message explaining why a check is being forced.
416 */
417static void check_if_skip(ext2_filsys fs)
418{
419 const char *reason = NULL;
420
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000421 if (force || bad_blocks_file || cflag || swapfs)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000422 return;
423
424 if (fs->super->s_state & EXT2_ERROR_FS)
425 reason = "contains a file system with errors";
426 else if (fs->super->s_mnt_count >=
427 (unsigned) fs->super->s_max_mnt_count)
428 reason = "has reached maximal mount count";
429 else if (fs->super->s_checkinterval &&
430 time(0) >= (fs->super->s_lastcheck +
431 fs->super->s_checkinterval))
432 reason = "has gone too long without being checked";
Theodore Ts'o5c576471997-04-29 15:29:49 +0000433 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
434 reason = "was not cleanly unmounted";
Theodore Ts'o3839e651997-04-26 13:21:57 +0000435 if (reason) {
436 printf("%s %s, check forced.\n", device_name, reason);
437 return;
438 }
Theodore Ts'o5c576471997-04-29 15:29:49 +0000439 printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name,
440 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
441 fs->super->s_inodes_count,
442 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
443 fs->super->s_blocks_count);
444 ext2fs_close(fs);
445 exit(FSCK_OK);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000446}
447
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000448#define PATH_SET "PATH=/sbin"
449
Theodore Ts'o3839e651997-04-26 13:21:57 +0000450static void PRS(int argc, char *argv[])
451{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000452 int flush = 0;
453 char c;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000454#ifdef MTRACE
Theodore Ts'of3db3561997-04-26 13:34:30 +0000455 extern void *mallwatch;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000456#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000457 char *oldpath = getenv("PATH");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000458
459 /* Update our PATH to include /sbin */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000460 if (oldpath) {
461 char *newpath;
462
463 newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
464 if (!newpath)
465 fatal_error("Couldn't malloc() newpath");
466 strcpy (newpath, PATH_SET);
467 strcat (newpath, ":");
468 strcat (newpath, oldpath);
469 putenv (newpath);
470 } else
471 putenv (PATH_SET);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000472
473 setbuf(stdout, NULL);
474 setbuf(stderr, NULL);
475 initialize_ext2_error_table();
476
477 if (argc && *argv)
478 program_name = *argv;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000479 while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000480 switch (c) {
481 case 'p':
482 case 'a':
483 preen = 1;
484 yflag = nflag = 0;
485 break;
486 case 'n':
487 nflag = 1;
488 preen = yflag = 0;
489 break;
490 case 'y':
491 yflag = 1;
492 preen = nflag = 0;
493 break;
494 case 't':
495 tflag++;
496 break;
497 case 'c':
498 cflag++;
499 break;
500 case 'r':
501 /* What we do by default, anyway! */
502 break;
503 case 'b':
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000504 use_superblock = atoi(optarg);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000505 break;
506 case 'B':
507 blocksize = atoi(optarg);
508 break;
509 case 'I':
510 inode_buffer_blocks = atoi(optarg);
511 break;
512 case 'P':
513 process_inode_size = atoi(optarg);
514 break;
515 case 'L':
516 replace_bad_blocks++;
517 case 'l':
518 bad_blocks_file = malloc(strlen(optarg)+1);
519 if (!bad_blocks_file)
520 fatal_error("Couldn't malloc bad_blocks_file");
521 strcpy(bad_blocks_file, optarg);
522 break;
523 case 'd':
524 debug = 1;
525 break;
526 case 'f':
527 force = 1;
528 break;
529 case 'F':
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000530#ifdef BLKFLSBUF
Theodore Ts'o3839e651997-04-26 13:21:57 +0000531 flush = 1;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000532#else
533 fatal_error ("-F not supported");
534#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000535 break;
536 case 'v':
537 verbose = 1;
538 break;
539 case 'V':
540 show_version_only = 1;
541 break;
542#ifdef MTRACE
543 case 'M':
544 mallwatch = (void *) strtol(optarg, NULL, 0);
545 break;
546#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000547 case 'N':
548 device_name = optarg;
549 break;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000550 case 's':
551 normalize_swapfs = 1;
552 case 'S':
553 swapfs = 1;
554 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000555 default:
556 usage ();
557 }
558 if (show_version_only)
559 return;
560 if (optind != argc - 1)
561 usage ();
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000562 if (nflag && !bad_blocks_file && !cflag && !swapfs)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000563 rwflag = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000564 filesystem_name = argv[optind];
565 if (device_name == 0)
566 device_name = filesystem_name;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000567 if (flush) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000568#ifdef BLKFLSBUF
569 int fd = open(filesystem_name, O_RDONLY, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000570
571 if (fd < 0) {
572 com_err("open", errno, "while opening %s for flushing",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000573 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000574 exit(FSCK_ERROR);
575 }
576 if (ioctl(fd, BLKFLSBUF, 0) < 0) {
577 com_err("BLKFLSBUF", errno, "while trying to flush %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000578 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000579 exit(FSCK_ERROR);
580 }
581 close(fd);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000582#else
583 fatal_error ("BLKFLSBUF not supported");
584#endif /* BLKFLSBUF */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000585 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000586 if (swapfs) {
587 if (cflag || bad_blocks_file) {
588 fprintf(stderr, "Incompatible options not "
589 "allowed when byte-swapping.\n");
590 fatal_error(0);
591 }
592 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000593}
594
595int main (int argc, char *argv[])
596{
597 errcode_t retval = 0;
598 int exit_value = FSCK_OK;
599 int i;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000600 ext2_filsys fs = 0;
601 io_manager io_ptr;
602 struct ext2fs_sb *s;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000603
604#ifdef MTRACE
605 mtrace();
606#endif
607#ifdef MCHECK
608 mcheck(0);
609#endif
610
611 init_resource_track(&global_rtrack);
612
613 PRS(argc, argv);
614
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000615 if (!preen || show_version_only)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000616 fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
617 E2FSPROGS_VERSION, E2FSPROGS_DATE,
618 EXT2FS_VERSION, EXT2FS_DATE);
619
Theodore Ts'o5c576471997-04-29 15:29:49 +0000620 if (show_version_only) {
621 fprintf(stderr, "\tUsing %s\n",
622 error_message(EXT2_ET_BASE));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000623 exit(0);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000624 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000625
626 check_mount();
627
628 if (!preen && !nflag && !yflag) {
629 if (!isatty (0) || !isatty (1))
630 die ("need terminal for interactive repairs");
631 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000632 superblock = use_superblock;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000633restart:
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000634#if 1
635 io_ptr = unix_io_manager;
636#else
637 io_ptr = test_io_manager;
638 test_io_backing_manager = unix_io_manager;
639#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000640 sync_disks();
641 if (superblock && blocksize) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000642 retval = ext2fs_open(filesystem_name,
643 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000644 superblock, blocksize, io_ptr, &fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000645 } else if (superblock) {
646 for (i=0; possible_block_sizes[i]; i++) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000647 retval = ext2fs_open(filesystem_name,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000648 rwflag ? EXT2_FLAG_RW : 0,
649 superblock,
650 possible_block_sizes[i],
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000651 io_ptr, &fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000652 if (!retval)
653 break;
654 }
655 } else
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000656 retval = ext2fs_open(filesystem_name,
657 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000658 0, 0, io_ptr, &fs);
659 if (!superblock && !preen &&
660 ((retval == EXT2_ET_BAD_MAGIC) ||
661 ((retval == 0) && ext2fs_check_desc(fs)))) {
662 if (!fs || (fs->group_desc_count > 1)) {
663 printf("%s trying backup blocks...\n",
664 retval ? "Couldn't find ext2 superblock," :
665 "Group descriptors look bad...");
666 superblock = 8193;
667 if (fs)
668 ext2fs_close(fs);
669 goto restart;
670 }
671 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000672 if (retval) {
673 com_err(program_name, retval, "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000674 filesystem_name);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000675 if (retval == EXT2_ET_REV_TOO_HIGH)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000676 printf ("Get a newer version of e2fsck!\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000677 else if (retval == EXT2_ET_SHORT_READ)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000678 printf ("Could this be a zero-length partition?\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000679 else if ((retval == EPERM) || (retval == EACCES))
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000680 printf("You must have %s access to the "
681 "filesystem or be root\n",
682 rwflag ? "r/w" : "r/o");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000683 else if (retval == ENXIO)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000684 printf("Possibly non-existent or swap device?\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000685 else
Theodore Ts'of3db3561997-04-26 13:34:30 +0000686 printf(corrupt_msg);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000687 fatal_error(0);
688 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000689#ifdef EXT2_CURRENT_REV
690 if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000691 com_err(program_name, EXT2_ET_REV_TOO_HIGH,
692 "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000693 filesystem_name);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000694 goto get_newer;
695 }
696#endif
697 /*
698 * Check for compatibility with the feature sets. We have to
699 * check because we need to be more stringent than ext2fs_open
700 */
701 s = (struct ext2fs_sb *) fs->super;
702 if (s->s_feature_compat || s->s_feature_incompat ||
703 s->s_feature_ro_compat) {
704 com_err(program_name, EXT2_ET_UNSUPP_FEATURE,
705 " (%s)", filesystem_name);
706 get_newer:
Theodore Ts'of3db3561997-04-26 13:34:30 +0000707 printf ("Get a newer version of e2fsck!\n");
708 fatal_error(0);
709 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000710
Theodore Ts'o3839e651997-04-26 13:21:57 +0000711 /*
712 * If the user specified a specific superblock, presumably the
713 * master superblock has been trashed. So we mark the
714 * superblock as dirty, so it can be written out.
715 */
716 if (superblock && rwflag)
717 ext2fs_mark_super_dirty(fs);
718
Theodore Ts'o5c576471997-04-29 15:29:49 +0000719 /*
720 * Don't overwrite the backup superblock and block
721 * descriptors, until we're sure the filesystem is OK....
722 */
723 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
724
Theodore Ts'o3839e651997-04-26 13:21:57 +0000725 ehandler_init(fs->io);
726
Theodore Ts'of3db3561997-04-26 13:34:30 +0000727 invalid_inode_bitmap = allocate_memory(sizeof(int) *
728 fs->group_desc_count,
729 "invalid_inode_bitmap");
730 invalid_block_bitmap = allocate_memory(sizeof(int) *
731 fs->group_desc_count,
732 "invalid_block_bitmap");
733 invalid_inode_table = allocate_memory(sizeof(int) *
734 fs->group_desc_count,
735 "invalid_inode_table");
736
Theodore Ts'o3839e651997-04-26 13:21:57 +0000737 check_super_block(fs);
738 check_if_skip(fs);
739 if (bad_blocks_file)
740 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
741 else if (cflag)
742 test_disk(fs);
743
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000744 if (normalize_swapfs) {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000745 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ==
746 ext2fs_native_flag()) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000747 fprintf(stderr, "%s: Filesystem byte order "
748 "already normalized.\n", device_name);
749 fatal_error(0);
750 }
751 }
752 if (swapfs)
753 swap_filesys(fs);
754
Theodore Ts'o3839e651997-04-26 13:21:57 +0000755 /*
756 * Mark the system as valid, 'til proven otherwise
757 */
758 ext2fs_mark_valid(fs);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000759
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000760 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
761 if (retval) {
762 com_err(program_name, retval,
763 "while reading bad blocks inode");
764 preenhalt(fs);
765 printf("This doesn't bode well, but we'll try to go on...\n");
766 }
767
Theodore Ts'o3839e651997-04-26 13:21:57 +0000768 pass1(fs);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000769 free(invalid_inode_bitmap);
770 free(invalid_block_bitmap);
771 free(invalid_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000772 if (restart_e2fsck) {
773 ext2fs_close(fs);
774 printf("Restarting e2fsck from the beginning...\n");
775 restart_e2fsck = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000776 superblock = use_superblock;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000777 goto restart;
778 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000779 pass2(fs);
780 pass3(fs);
781 pass4(fs);
782 pass5(fs);
783
784#ifdef MTRACE
785 mtrace_print("Cleanup");
786#endif
787 if (ext2fs_test_changed(fs)) {
788 exit_value = FSCK_NONDESTRUCT;
789 if (!preen)
790 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
791 device_name);
792 if (root_filesystem && !read_only_root) {
793 printf("%s: ***** REBOOT LINUX *****\n", device_name);
794 exit_value = FSCK_REBOOT;
795 }
796 }
Theodore Ts'o5c576471997-04-29 15:29:49 +0000797 if (ext2fs_test_valid(fs))
798 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
799 else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000800 exit_value = FSCK_UNCORRECTED;
801 if (rwflag) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000802 if (ext2fs_test_valid(fs)) {
803 if (!(fs->super->s_state & EXT2_VALID_FS))
804 exit_value = FSCK_NONDESTRUCT;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000805 fs->super->s_state = EXT2_VALID_FS;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000806 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000807 fs->super->s_state &= ~EXT2_VALID_FS;
808 fs->super->s_mnt_count = 0;
809 fs->super->s_lastcheck = time(NULL);
810 ext2fs_mark_super_dirty(fs);
811 }
812 show_stats(fs);
813
814 write_bitmaps(fs);
815 ext2fs_close(fs);
816 sync_disks();
817
818 if (tflag)
819 print_resource_track(&global_rtrack);
820
821 return exit_value;
822}