We dump failure messages to the terminal regardless of whether the caller wants them or not. This can be annoying when used as part of a general tool that tests to see which file system is on a device by calling its open routine. Signed-off-by: Jeff Mahoney <jeffm@suse.com>
1476 lines
40 KiB
C
1476 lines
40 KiB
C
/*
|
|
* Copyright 1996-2004 by Hans Reiser, licensing governed by
|
|
* reiserfsprogs/README
|
|
*/
|
|
|
|
#include "fsck.h"
|
|
#include <getopt.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/mman.h>
|
|
#include <signal.h>
|
|
#include <limits.h>
|
|
|
|
extern int screen_width;
|
|
extern int screen_savebuffer_len;
|
|
extern char *screen_savebuffer;
|
|
|
|
reiserfs_filsys_t fs;
|
|
static char *badblocks_file;
|
|
|
|
#define print_usage_and_exit() { \
|
|
fsck_progress ("Usage: %s [mode] [options] " \
|
|
" device\n" \
|
|
"\n" \
|
|
"Modes:\n" \
|
|
" --check\t\t\tconsistency checking (default)\n" \
|
|
" --fix-fixable\t\t\tfix corruptions which can be fixed without \n" \
|
|
" \t\t\t\t--rebuild-tree\n" \
|
|
" --rebuild-sb\t\t\tsuper block checking and rebuilding if needed\n" \
|
|
" \t\t\t\t(may require --rebuild-tree afterwards)\n" \
|
|
" --rebuild-tree\t\tforce fsck to rebuild filesystem from scratch\n" \
|
|
" \t\t\t\t(takes a long time)\n" \
|
|
" --clean-attributes\t\tclean garbage in reserved fields in StatDatas \n" \
|
|
"Options:\n" \
|
|
" -j | --journal device\t\tspecify journal if relocated\n" \
|
|
" -B | --badblocks file\t\tfile with list of all bad blocks on the fs\n" \
|
|
" -l | --logfile file\t\tmake fsck to complain to specifed file\n" \
|
|
" -n | --nolog\t\t\tmake fsck to not complain\n" \
|
|
" -z | --adjust-size\t\tfix file sizes to real size\n" \
|
|
" -q | --quiet\t\t\tno speed info\n" \
|
|
" -y | --yes\t\t\tno confirmations\n" \
|
|
" -f | --force\t\tforce checking even if the file system is marked clean\n"\
|
|
" -V\t\t\t\tprints version and exits\n" \
|
|
" -a and -p\t\t\tsome light-weight auto checks for bootup\n" \
|
|
" -r\t\t\tignored\n" \
|
|
"Expert options:\n" \
|
|
" --no-journal-available\tdo not open nor replay journal\n" \
|
|
" -S | --scan-whole-partition\tbuild tree of all blocks of the device\n\n", \
|
|
argv[0]); \
|
|
\
|
|
exit(EXIT_OK); \
|
|
}
|
|
|
|
/*
|
|
-B works with --fix-fixable
|
|
fixes indirect pointers pointed to
|
|
badblocks, adds badblocks to badblock list in fs.
|
|
and with --rebuild
|
|
builds the tree without pointers to badblocks (internal,
|
|
indirect), adds badblocks to badblock list in fs.
|
|
*/
|
|
|
|
/*
|
|
Hidden usage:
|
|
Modes:
|
|
" --rollback-fsck-changes\n\t\t\trollback all changes made by fsck\n"\
|
|
Options:
|
|
" -b | --scan-marked-in-bitmap file\n"\
|
|
" \t\t\tbuild tree of blocks marked in the bitmapfile\n"\
|
|
" -R | --rollback-data file\n"\
|
|
" \t\t\tback up all changes to this file or rollback from this file\n"\
|
|
" \t\t\tpreviously backed up changes with --rollback-fsck-changes\n"\
|
|
" -d dumpfile\n"\
|
|
" \t\t\tto test fsck pass by pass - dump into dumpfile all needed\n"\
|
|
" \t\t\tinfo for the next pass and load on the start of the next pass\n"\
|
|
" -i | --interactive\tmake fsck to stop after every stage\n"\
|
|
" -h | --hash hashname\n"\
|
|
" -g | --background\n"\
|
|
" -t \t\tdo test\n"\
|
|
*/
|
|
|
|
/* fsck is called with one non-optional argument - file name of device
|
|
containing reiserfs. This function parses other options, sets flags
|
|
based on parsing and returns non-optional argument */
|
|
static char *parse_options(struct fsck_data *data, int argc, char *argv[])
|
|
{
|
|
int c;
|
|
static int mode = FSCK_CHECK;
|
|
static int flag;
|
|
|
|
data->rebuild.scan_area = USED_BLOCKS;
|
|
while (1) {
|
|
static struct option options[] = {
|
|
/* modes */
|
|
{"check", no_argument, &mode, FSCK_CHECK},
|
|
{"fix-fixable", no_argument, &mode, FSCK_FIX_FIXABLE},
|
|
{"rebuild-sb", no_argument, &mode, FSCK_SB},
|
|
{"rebuild-tree", no_argument, &mode, FSCK_REBUILD},
|
|
{"rollback-fsck-changes", no_argument, &mode,
|
|
FSCK_ROLLBACK_CHANGES},
|
|
{"clean-attributes", no_argument, &mode,
|
|
FSCK_CLEAN_ATTRIBUTES},
|
|
/* options */
|
|
{"logfile", required_argument, NULL, 'l'},
|
|
{"badblocks", required_argument, NULL, 'B'},
|
|
{"interactive", no_argument, NULL, 'i'},
|
|
{"adjust-size", no_argument, NULL, 'z'},
|
|
{"quiet", no_argument, NULL, 'q'},
|
|
{"yes", no_argument, NULL, 'y'},
|
|
{"force", no_argument, NULL, 'f'},
|
|
{"nolog", no_argument, NULL, 'n'},
|
|
|
|
/* if file exists ad reiserfs can be load of it - only
|
|
blocks marked used in that bitmap will be read */
|
|
{"scan-marked-in-bitmap", required_argument, NULL, 'b'},
|
|
|
|
{"create-passes-dump", required_argument, NULL, 'd'},
|
|
|
|
/* all blocks will be read */
|
|
{"scan-whole-partition", no_argument, NULL, 'S'},
|
|
/* useful for -S */
|
|
{"hash", required_argument, NULL, 'h'},
|
|
|
|
/* preparing rollback data */
|
|
{"rollback-data", required_argument, NULL, 'R'},
|
|
|
|
{"journal", required_argument, NULL, 'j'},
|
|
{"no-journal-available", no_argument, &flag,
|
|
OPT_SKIP_JOURNAL},
|
|
|
|
{"bad-block-file", required_argument, NULL, 'B'},
|
|
|
|
/* start reiserfsck in background and exit */
|
|
{"background", no_argument, NULL, 'g'},
|
|
|
|
{}
|
|
};
|
|
int option_index;
|
|
|
|
c = getopt_long(argc, argv, "iql:nb:Szd:R:h:j:gafVrpyt:B:",
|
|
options, &option_index);
|
|
if (c == -1)
|
|
break;
|
|
|
|
switch (c) {
|
|
case 0:
|
|
/* long-only options */
|
|
if (flag == OPT_SKIP_JOURNAL) {
|
|
/* no journal available */
|
|
data->options |= OPT_SKIP_JOURNAL;
|
|
flag = 0;
|
|
}
|
|
break;
|
|
|
|
case 'i': /* --interactive */
|
|
data->options |= OPT_INTERACTIVE;
|
|
break;
|
|
|
|
case 'q': /* --quiet */
|
|
data->options |= OPT_QUIET;
|
|
break;
|
|
|
|
case 'y': /* --quiet */
|
|
data->options |= OPT_YES;
|
|
break;
|
|
|
|
case 'l': /* --logfile */
|
|
data->log_file_name = optarg;
|
|
/*asprintf (&data->log_file_name, "%s", optarg); */
|
|
data->log = fopen(optarg, "w");
|
|
if (!data->log)
|
|
fprintf(stderr,
|
|
"reiserfsck: Cannot not open \'%s\': %s",
|
|
optarg, strerror(errno));
|
|
break;
|
|
|
|
case 'n': /* --nolog */
|
|
data->options |= OPT_SILENT;
|
|
break;
|
|
|
|
case 'b': /* --scan-marked-in-bitmap */
|
|
/* will try to load a bitmap from a file and read only
|
|
blocks marked in it. That bitmap could be created by
|
|
previous run of reiserfsck with -c */
|
|
data->rebuild.bitmap_file_name = optarg;
|
|
/*asprintf (&data->rebuild.bitmap_file_name, "%s", optarg); */
|
|
data->rebuild.scan_area = EXTERN_BITMAP;
|
|
break;
|
|
|
|
case 'S': /* --scan-whole-partition */
|
|
data->rebuild.scan_area = ALL_BLOCKS;
|
|
break;
|
|
|
|
#if 0
|
|
case 'J': /* take all blocks which are leaves in journal area and put
|
|
them into tree item by item (DO NOT USE IT UNTIL YOU KNOW
|
|
WHAT ARE YOU DOING) */
|
|
data->rebuild.use_journal_area = 1;
|
|
break;
|
|
#endif
|
|
case 'd': /* --create-passes-dump */
|
|
asprintf(&data->rebuild.passes_dump_file_name, "%s",
|
|
optarg);
|
|
data->options |= OPT_SAVE_PASSES_DUMP;
|
|
break;
|
|
|
|
case 'z': /* --adjust-file-size */
|
|
data->options |= OPT_ADJUST_FILE_SIZE;
|
|
break;
|
|
|
|
case 'h': /* --hash: suppose that this hash was used on a filesystem */
|
|
asprintf(&data->rebuild.defined_hash, "%s", optarg);
|
|
if (name2func(data->rebuild.defined_hash) == NULL)
|
|
reiserfs_panic
|
|
("reiserfsck: Unknown hash is specified: %s",
|
|
data->rebuild.defined_hash);
|
|
data->options |= OPT_HASH_DEFINED;
|
|
break;
|
|
|
|
case 'j': /* specified relocated journal device */
|
|
data->journal_dev_name = optarg;
|
|
break;
|
|
|
|
case 'R': /* preparing rollback data */
|
|
asprintf(&data->rebuild.rollback_file, "%s", optarg);
|
|
data->options |= OPT_SAVE_ROLLBACK;
|
|
break;
|
|
|
|
case 'B': /* list of phisically corrupted blocks */
|
|
asprintf(&badblocks_file, "%s", optarg);
|
|
data->options |= BADBLOCKS_FILE;
|
|
break;
|
|
|
|
case 'g': /* --background */
|
|
data->options |= OPT_BACKGROUND;
|
|
break;
|
|
|
|
case 'a':
|
|
case 'p':
|
|
data->options |= OPT_QUIET;
|
|
mode = FSCK_AUTO;
|
|
break;
|
|
|
|
case 'f':
|
|
data->options |= OPT_FORCE;
|
|
break;
|
|
case 'r': /* ignored */
|
|
break;
|
|
|
|
case 'V': /* cause fsck to do nothing */
|
|
mode = DO_NOTHING;
|
|
break;
|
|
|
|
case 't':
|
|
mode = DO_TEST;
|
|
data->rebuild.test = atoi(optarg);
|
|
break;
|
|
|
|
default:
|
|
print_usage_and_exit();
|
|
}
|
|
}
|
|
|
|
if (optind != argc - 1 && mode != DO_NOTHING)
|
|
/* only one non-option argument is permitted */
|
|
print_usage_and_exit();
|
|
|
|
if (mode != FSCK_REBUILD &&
|
|
(data->rebuild.scan_area == EXTERN_BITMAP ||
|
|
data->rebuild.scan_area == ALL_BLOCKS ||
|
|
data->options & OPT_SAVE_PASSES_DUMP))
|
|
/* wrong options for this mode */
|
|
print_usage_and_exit();
|
|
|
|
/*
|
|
if (data->options & OPT_ADJUST_FILE_SIZE) {
|
|
if ((mode != FSCK_REBUILD) && (mode != FSCK_FIX_FIXABLE))
|
|
print_usage_and_exit();
|
|
}
|
|
*/
|
|
|
|
if (data->options & OPT_SAVE_ROLLBACK) {
|
|
if (mode == FSCK_SB)
|
|
print_usage_and_exit();
|
|
}
|
|
|
|
if (mode == FSCK_ROLLBACK_CHANGES) {
|
|
if ((data->options & OPT_SAVE_ROLLBACK) == 0)
|
|
print_usage_and_exit();
|
|
}
|
|
|
|
if ((data->options & BADBLOCKS_FILE) && mode != FSCK_REBUILD &&
|
|
mode != FSCK_FIX_FIXABLE) {
|
|
fprintf(stderr,
|
|
"Badblocks can be specified with --fix-fixable or "
|
|
"--rebuild-tree only.\n");
|
|
print_usage_and_exit();
|
|
}
|
|
|
|
if ((mode == FSCK_REBUILD) && (data->options & OPT_YES))
|
|
data->options &= ~OPT_YES;
|
|
|
|
data->mode = mode;
|
|
if (!data->log)
|
|
data->log = stdout;
|
|
|
|
return argv[optind];
|
|
}
|
|
|
|
#define REBUILD_WARNING \
|
|
"*************************************************************\n\
|
|
** Do not run the program with --rebuild-tree unless **\n\
|
|
** something is broken and MAKE A BACKUP before using it. **\n\
|
|
** If you have bad sectors on a drive it is usually a bad **\n\
|
|
** idea to continue using it. Then you probably should get **\n\
|
|
** a working hard drive, copy the file system from the bad **\n\
|
|
** drive to the good one -- dd_rescue is a good tool for **\n\
|
|
** that -- and only then run this program. **\n\
|
|
*************************************************************\n\
|
|
\nWill rebuild the filesystem (%s) tree\n"
|
|
static void warn_what_will_be_done(char *file_name, struct fsck_data *data)
|
|
{
|
|
FILE *warn_to;
|
|
|
|
warn_to = (data->progress ? data->progress : stderr);
|
|
|
|
if (data->mode == FSCK_REBUILD)
|
|
reiserfs_warning(warn_to, REBUILD_WARNING, file_name);
|
|
|
|
/* warn about fsck mode */
|
|
switch (data->mode) {
|
|
case FSCK_CHECK:
|
|
reiserfs_warning(warn_to,
|
|
"Will read-only check consistency of the "
|
|
"filesystem on %s\n", file_name);
|
|
|
|
break;
|
|
|
|
case FSCK_FIX_FIXABLE:
|
|
|
|
reiserfs_warning(warn_to,
|
|
"Will check consistency of the filesystem "
|
|
"on %s\n", file_name);
|
|
reiserfs_warning(warn_to,
|
|
"and will fix what can be fixed without "
|
|
"--rebuild-tree\n");
|
|
|
|
break;
|
|
|
|
case FSCK_SB:
|
|
reiserfs_warning(warn_to,
|
|
"Will check superblock and rebuild it if "
|
|
"needed\n");
|
|
|
|
break;
|
|
|
|
case FSCK_REBUILD:
|
|
if (data->options & OPT_SAVE_PASSES_DUMP) {
|
|
reiserfs_warning(warn_to,
|
|
"Will run only 1 step of the rebuilding, "
|
|
"write state file '%s' and exit\n",
|
|
data->rebuild.passes_dump_file_name);
|
|
} else if (data->options & OPT_INTERACTIVE)
|
|
reiserfs_warning(warn_to,
|
|
"Will stop after every stage and ask for "
|
|
"confirmation before continuing\n");
|
|
|
|
if (data->rebuild.bitmap_file_name)
|
|
reiserfs_warning(warn_to,
|
|
"Will try to load a bitmap--of all "
|
|
"ReiserFS leaves in the partition--from the file \n'%s'\n",
|
|
data->rebuild.bitmap_file_name);
|
|
|
|
if (data->options & OPT_ADJUST_FILE_SIZE)
|
|
reiserfs_warning(warn_to,
|
|
"\tWill set file sizes in their metadata "
|
|
"to real file sizes actually found by fsck.\n");
|
|
|
|
if (data->options & OPT_HASH_DEFINED)
|
|
reiserfs_warning(warn_to,
|
|
"\tSuppose \"%s\" hash is in use\n",
|
|
data->rebuild.defined_hash);
|
|
|
|
break;
|
|
|
|
case FSCK_ROLLBACK_CHANGES:
|
|
reiserfs_warning(warn_to,
|
|
"Will rollback all data saved in %s into %s\n",
|
|
data->rebuild.rollback_file, file_name);
|
|
|
|
break;
|
|
case FSCK_CLEAN_ATTRIBUTES:
|
|
reiserfs_warning(warn_to, "Will clean file attributes on %s\n",
|
|
file_name);
|
|
break;
|
|
case FSCK_AUTO:
|
|
return;
|
|
}
|
|
|
|
if (data->options & OPT_SAVE_ROLLBACK
|
|
&& data->mode != FSCK_ROLLBACK_CHANGES)
|
|
reiserfs_warning(warn_to,
|
|
"Will save all blocks to be changed into "
|
|
"file '%s'\n", data->rebuild.rollback_file);
|
|
|
|
if (data->options & BADBLOCKS_FILE)
|
|
reiserfs_warning(warn_to,
|
|
"Bad block list will contain only blocks specified in '%s' "
|
|
"file\n", badblocks_file);
|
|
|
|
reiserfs_warning(warn_to, "Will put log info to '%s'\n",
|
|
(data->log == stdout) ? "stdout" :
|
|
(data->log_file_name ? data->
|
|
log_file_name : "fsck.run"));
|
|
|
|
if (!(data->options & OPT_YES) && !(data->options & OPT_SILENT) &&
|
|
!user_confirmed(warn_to,
|
|
"\nDo you want to run this program?[N/Yes] "
|
|
"(note need to type Yes if you do):", "Yes\n"))
|
|
exit(EXIT_USER);
|
|
}
|
|
|
|
static dma_info_t dma_info;
|
|
static dma_info_t old_dma_info;
|
|
|
|
static void check_dma(int sig)
|
|
{
|
|
old_dma_info = dma_info;
|
|
if (get_dma_info(&dma_info) == -1) {
|
|
fsck_log("get_dma_info failed %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
if (dma_info.dma != old_dma_info.dma) {
|
|
if (dma_info.dma == 0) {
|
|
printf
|
|
("\n********************************************************************\n");
|
|
printf
|
|
("* Warning: It was just detected that dma mode was turned off while *\n");
|
|
printf
|
|
("* operating -- probably due to some problem with your hardware. *\n");
|
|
printf
|
|
("* Please check your hardware and have a look into the syslog file. *\n");
|
|
printf
|
|
("* Note: running with --rebuild-tree on faulty hardware may destroy *\n");
|
|
printf
|
|
("* your data. *\n");
|
|
printf
|
|
("********************************************************************\n");
|
|
if (fsck_log_file(fs) != stdout)
|
|
fsck_log
|
|
("WARNING: dma mode has been turned off.\n");
|
|
}
|
|
}
|
|
if (dma_info.speed != old_dma_info.speed) {
|
|
if (dma_info.speed < old_dma_info.speed) {
|
|
printf
|
|
("\n********************************************************************\n");
|
|
printf
|
|
("* Warning: It was just detected that dma speed was descreased while*\n");
|
|
printf
|
|
("* operating -- probably due to some problem with your hardware. *\n");
|
|
printf
|
|
("* Please check your hardware and have a look into the syslog file. *\n");
|
|
printf
|
|
("* Note: running with --rebuild-tree on faulty hardware may destroy *\n");
|
|
printf
|
|
("* your data. *\n");
|
|
printf
|
|
("********************************************************************\n");
|
|
if (fsck_log_file(fs) != stdout)
|
|
fsck_log
|
|
("WARNING: dma speed has been descreased.\n");
|
|
}
|
|
}
|
|
|
|
alarm(1);
|
|
}
|
|
|
|
static void register_timer(void)
|
|
{
|
|
memset(&dma_info, 0, sizeof(dma_info));
|
|
memset(&old_dma_info, 0, sizeof(old_dma_info));
|
|
|
|
dma_info.fd = fs->fs_dev;
|
|
|
|
if (prepare_dma_check(&dma_info) != 0)
|
|
return;
|
|
|
|
if (get_dma_info(&dma_info) == -1) {
|
|
fsck_log("get_dma_info failed %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
if (dma_info.dma == 0) {
|
|
printf
|
|
("\n******************************************************\n");
|
|
printf
|
|
("* Warning: The dma on your hard drive is turned off. *\n");
|
|
printf
|
|
("* This may really slow down the fsck process. *\n");
|
|
printf
|
|
("******************************************************\n");
|
|
if (fsck_log_file(fs) != stdout)
|
|
fsck_log("WARNING: DMA is turned off\n");
|
|
}
|
|
|
|
signal(SIGALRM, check_dma);
|
|
alarm(1);
|
|
}
|
|
|
|
static void reset_super_block(reiserfs_filsys_t fs)
|
|
{
|
|
struct reiserfs_super_block *sb;
|
|
struct reiserfs_journal_header *jh;
|
|
|
|
sb = fs->fs_ondisk_sb;
|
|
|
|
set_sb_free_blocks(sb, get_sb_block_count(sb));
|
|
set_sb_root_block(sb, 0);
|
|
set_sb_tree_height(sb, ~0);
|
|
|
|
/* make file system invalid unless fsck finished () */
|
|
set_sb_fs_state(sb, get_sb_fs_state(sb) | FS_FATAL);
|
|
|
|
/*
|
|
if ( is_reiser2fs_jr_magic_string (sb) ) {???
|
|
set_sb_version (sb, REISERFS_VERSION_3);
|
|
}
|
|
if (is_reiser2fs_magic_string (sb)) {
|
|
set_sb_version (sb, REISERFS_FORMAT_3_6);
|
|
}
|
|
if (is_reiserfs_magic_string (sb)) {
|
|
set_sb_version (sb, REISERFS_FORMAT_3_5);
|
|
}
|
|
*/
|
|
/* make sure that hash code in super block match to set hash function */
|
|
set_sb_hash_code(sb, func2code(fs->fs_hash_function));
|
|
|
|
if (fsck_hash_defined(fs)) {
|
|
/* --hash was specifed */
|
|
fs->fs_hash_function =
|
|
name2func(fsck_data(fs)->rebuild.defined_hash);
|
|
set_sb_hash_code(sb, func2code(fs->fs_hash_function));
|
|
}
|
|
|
|
if (reiserfs_journal_opened(fs)) {
|
|
jh = (struct reiserfs_journal_header *)fs->fs_jh_bh->b_data;
|
|
|
|
/* reset journal params if needed. */
|
|
if (memcmp
|
|
(sb_jp(sb), &jh->jh_journal,
|
|
sizeof(struct journal_params))) {
|
|
if (is_reiserfs_jr_magic_string(sb))
|
|
memcpy(sb_jp(sb), &jh->jh_journal,
|
|
sizeof(struct journal_params));
|
|
else {
|
|
set_sb_reserved_for_journal(sb, 0);
|
|
|
|
set_jp_journal_dev(sb_jp(sb), 0);
|
|
set_jp_journal_magic(sb_jp(sb), get_random());
|
|
set_jp_journal_1st_block(sb_jp(sb),
|
|
get_journal_start_must
|
|
(fs));
|
|
set_jp_journal_size(sb_jp(sb),
|
|
journal_default_size(fs->
|
|
fs_super_bh->
|
|
b_blocknr,
|
|
fs->
|
|
fs_blocksize));
|
|
set_jp_journal_max_trans_len(sb_jp(sb),
|
|
advise_journal_max_trans_len
|
|
(get_jp_journal_max_trans_len
|
|
(sb_jp(sb)),
|
|
get_jp_journal_size
|
|
(sb_jp(sb)),
|
|
fs->fs_blocksize,
|
|
0));
|
|
set_jp_journal_max_batch(sb_jp(sb),
|
|
advise_journal_max_batch
|
|
(get_jp_journal_max_trans_len
|
|
(sb_jp(sb))));
|
|
set_jp_journal_max_commit_age(sb_jp(sb),
|
|
advise_journal_max_commit_age
|
|
());
|
|
set_jp_journal_max_trans_age(sb_jp(sb),
|
|
advise_journal_max_trans_age
|
|
());
|
|
|
|
set_jp_journal_dev(&jh->jh_journal, 0);
|
|
set_jp_journal_magic(&jh->jh_journal,
|
|
get_jp_journal_magic(sb_jp
|
|
(sb)));
|
|
set_jp_journal_1st_block(&jh->jh_journal,
|
|
get_jp_journal_1st_block
|
|
(sb_jp(sb)));
|
|
set_jp_journal_size(&jh->jh_journal,
|
|
get_jp_journal_size(sb_jp
|
|
(sb)));
|
|
set_jp_journal_max_trans_len(&jh->jh_journal,
|
|
get_jp_journal_max_trans_len
|
|
(sb_jp(sb)));
|
|
set_jp_journal_max_batch(&jh->jh_journal,
|
|
get_jp_journal_max_batch
|
|
(sb_jp(sb)));
|
|
set_jp_journal_max_commit_age(&jh->jh_journal,
|
|
get_jp_journal_max_commit_age
|
|
(sb_jp(sb)));
|
|
set_jp_journal_max_trans_age(&jh->jh_journal,
|
|
get_jp_journal_max_trans_age
|
|
(sb_jp(sb)));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* objectid map is not touched */
|
|
mark_buffer_dirty(fs->fs_super_bh);
|
|
bwrite(fs->fs_super_bh);
|
|
if (!(fsck_data(fs)->options & OPT_SAVE_PASSES_DUMP))
|
|
mark_buffer_do_not_flush(fs->fs_super_bh);
|
|
}
|
|
|
|
#define START_FROM_THE_BEGINNING 1
|
|
#define START_FROM_PASS_1 2
|
|
#define START_FROM_PASS_2 3
|
|
#define START_FROM_SEMANTIC 4
|
|
#define START_FROM_LOST_FOUND 5
|
|
#define START_FROM_PASS_4 6
|
|
|
|
/* this decides where to start from */
|
|
static int where_to_start_from(reiserfs_filsys_t fs)
|
|
{
|
|
int ret;
|
|
FILE *fp = NULL;
|
|
int last_run_state;
|
|
|
|
last_run_state = get_sb_fs_state(fs->fs_ondisk_sb);
|
|
if (last_run_state == 0 || !fsck_run_one_step(fs))
|
|
/**/ return START_FROM_THE_BEGINNING;
|
|
|
|
/* We are able to perform the next step only if there is a file with the previous
|
|
* step results. */
|
|
fp = open_file(state_dump_file(fs), "r");
|
|
if (fp == NULL) {
|
|
set_sb_fs_state(fs->fs_ondisk_sb, 0);
|
|
return START_FROM_THE_BEGINNING;
|
|
}
|
|
|
|
/* check start and end magics of dump file */
|
|
ret = is_stage_magic_correct(fp);
|
|
|
|
if (ret <= 0 || ret != last_run_state)
|
|
return START_FROM_THE_BEGINNING;
|
|
|
|
switch (last_run_state) {
|
|
case PASS_0_DONE:
|
|
/* skip pass 0 */
|
|
if (!fsck_user_confirmed
|
|
(fs, "Pass 0 seems finished. Start from pass 1?(Yes)",
|
|
"Yes\n", 1))
|
|
fsck_exit("Run without -d then\n");
|
|
|
|
load_pass_0_result(fp, fs);
|
|
fclose(fp);
|
|
return START_FROM_PASS_1;
|
|
|
|
case PASS_1_DONE:
|
|
/* skip pass 1 */
|
|
if (!fsck_user_confirmed
|
|
(fs,
|
|
"Passes 0 and 1 seems finished. Start from "
|
|
"pass 2?(Yes)", "Yes\n", 1)) {
|
|
fsck_exit("Run without -d then\n");
|
|
}
|
|
|
|
load_pass_1_result(fp, fs);
|
|
fclose(fp);
|
|
return START_FROM_PASS_2;
|
|
|
|
case TREE_IS_BUILT:
|
|
if (!fsck_user_confirmed
|
|
(fs,
|
|
"Internal tree of filesystem looks built. "
|
|
"Skip rebuilding?(Yes)", "Yes\n", 1)) {
|
|
fsck_exit("Run without -d then\n");
|
|
}
|
|
|
|
load_pass_2_result(fs);
|
|
fclose(fp);
|
|
return START_FROM_SEMANTIC;
|
|
case SEMANTIC_DONE:
|
|
if (!fsck_user_confirmed
|
|
(fs,
|
|
"Passes 0 and 1 seems finished. Start from "
|
|
"pass 2?(Yes)", "Yes\n", 1)) {
|
|
fsck_exit("Run without -d then\n");
|
|
}
|
|
|
|
load_semantic_result(fp, fs);
|
|
fclose(fp);
|
|
return START_FROM_LOST_FOUND;
|
|
case LOST_FOUND_DONE:
|
|
if (!fsck_user_confirmed
|
|
(fs,
|
|
"Passes 0 and 1 seems finished. Start from "
|
|
"pass 2?(Yes)", "Yes\n", 1)) {
|
|
fsck_exit("Run without -d then\n");
|
|
}
|
|
|
|
load_lost_found_result(fs);
|
|
fclose(fp);
|
|
return START_FROM_PASS_4;
|
|
}
|
|
|
|
return START_FROM_THE_BEGINNING;
|
|
}
|
|
|
|
static void reiserfs_update_interval_fields(reiserfs_filsys_t fs)
|
|
{
|
|
/* Not supported on v3.5 */
|
|
if (get_sb_version(fs->fs_ondisk_sb) == REISERFS_FORMAT_3_5)
|
|
return;
|
|
|
|
set_sb_v2_lastcheck(fs->fs_ondisk_sb, time(NULL));
|
|
set_sb_v2_mnt_count(fs->fs_ondisk_sb, 1);
|
|
|
|
if (get_sb_v2_max_mnt_count(fs->fs_ondisk_sb) == 0)
|
|
set_sb_v2_max_mnt_count(fs->fs_ondisk_sb,
|
|
DEFAULT_MAX_MNT_COUNT);
|
|
if (get_sb_v2_check_interval(fs->fs_ondisk_sb) == 0)
|
|
set_sb_v2_check_interval(fs->fs_ondisk_sb,
|
|
DEFAULT_CHECK_INTERVAL);
|
|
}
|
|
|
|
static void mark_filesystem_consistent(reiserfs_filsys_t fs)
|
|
{
|
|
if (!is_opened_rw(fs))
|
|
return;
|
|
|
|
if (!reiserfs_journal_opened(fs)) {
|
|
/* make sure journal is not standard */
|
|
if (!is_reiserfs_jr_magic_string(fs->fs_ondisk_sb))
|
|
reiserfs_exit(EXIT_OPER,
|
|
"Filesystem with default journal "
|
|
"must be opened.");
|
|
|
|
fsck_progress
|
|
("WARNING: You must use reiserfstune to specify a new "
|
|
"journal before mounting it.\n");
|
|
|
|
/* mark filesystem such that it is not mountable until
|
|
* new journaldevice is defined */
|
|
set_jp_journal_magic(sb_jp(fs->fs_ondisk_sb), NEED_TUNE);
|
|
}
|
|
|
|
set_sb_umount_state(fs->fs_ondisk_sb, FS_CLEANLY_UMOUNTED);
|
|
set_sb_fs_state(fs->fs_ondisk_sb, FS_CONSISTENT);
|
|
reiserfs_update_interval_fields(fs);
|
|
|
|
mark_buffer_dirty(fs->fs_super_bh);
|
|
}
|
|
|
|
static void reiserfsck_replay_journal(reiserfs_filsys_t fs)
|
|
{
|
|
struct reiserfs_super_block *on_place_sb;
|
|
int sb_size = reiserfs_super_block_size(fs->fs_ondisk_sb);
|
|
|
|
/* keep the super_block in the separate memory to avoid problems with replaying
|
|
* broken parameters. */
|
|
on_place_sb = (struct reiserfs_super_block *)fs->fs_super_bh->b_data;
|
|
fs->fs_ondisk_sb = getmem(sb_size);
|
|
memcpy(fs->fs_ondisk_sb, on_place_sb, sb_size);
|
|
|
|
reiserfs_replay_journal(fs);
|
|
|
|
/* Copy checked reliable sb fields from backed up sb to a new one. */
|
|
set_sb_block_count(on_place_sb, get_sb_block_count(fs->fs_ondisk_sb));
|
|
memcpy(sb_jp(on_place_sb), sb_jp(fs->fs_ondisk_sb),
|
|
sizeof(struct journal_params));
|
|
set_sb_block_size(on_place_sb, get_sb_block_size(fs->fs_ondisk_sb));
|
|
set_sb_oid_maxsize(on_place_sb, get_sb_oid_maxsize(fs->fs_ondisk_sb));
|
|
memcpy(on_place_sb->s_v1.s_magic, fs->fs_ondisk_sb->s_v1.s_magic, 10);
|
|
set_sb_hash_code(on_place_sb, get_sb_hash_code(fs->fs_ondisk_sb));
|
|
set_sb_bmap_nr(on_place_sb, get_sb_bmap_nr(fs->fs_ondisk_sb));
|
|
set_sb_version(on_place_sb, get_sb_version(fs->fs_ondisk_sb));
|
|
set_sb_reserved_for_journal(on_place_sb,
|
|
get_sb_reserved_for_journal(fs->
|
|
fs_ondisk_sb));
|
|
|
|
if (sb_size == SB_SIZE) {
|
|
set_sb_v2_flags(on_place_sb, get_sb_v2_flags(fs->fs_ondisk_sb));
|
|
memcpy(on_place_sb->s_uuid, fs->fs_ondisk_sb->s_uuid, 16);
|
|
memcpy(on_place_sb->s_label, fs->fs_ondisk_sb->s_label, 16);
|
|
}
|
|
|
|
/* get rid of SB copy */
|
|
freemem(fs->fs_ondisk_sb);
|
|
fs->fs_ondisk_sb = on_place_sb;
|
|
}
|
|
|
|
static int the_end(reiserfs_filsys_t fs)
|
|
{
|
|
int ret = EXIT_FIXED;
|
|
|
|
/* put bitmap and objectid map on place */
|
|
reiserfs_delete_bitmap(fs->fs_bitmap2);
|
|
fs->fs_bitmap2 = fsck_new_bitmap(fs);
|
|
if (!fs->fs_bitmap2->bm_dirty)
|
|
die("Bitmap not dirty");
|
|
|
|
// id_map_flush(proper_id_map (fs), fs);
|
|
id_map_flush(semantic_id_map(fs), fs);
|
|
id_map_free(proper_id_map(fs));
|
|
id_map_free(semantic_id_map(fs));
|
|
|
|
/* set_sb_free_blocks (sb, reiserfs_bitmap_zeros (fsck_new_bitmap (fs)));*/
|
|
|
|
mark_filesystem_consistent(fs);
|
|
clear_buffer_do_not_flush(fs->fs_super_bh);
|
|
|
|
if (fsck_data(fs)->mounted == MF_RO) {
|
|
reiserfs_warning(stderr, "\nThe partition is mounted ro. It "
|
|
"is better to umount and mount it again.\n\n");
|
|
ret = EXIT_REBOOT;
|
|
}
|
|
|
|
/* write all dirty blocks */
|
|
fsck_progress("Syncing..");
|
|
fs->fs_dirt = 1;
|
|
clean_after_dma_check(fs->fs_dev, &dma_info);
|
|
fsck_progress("finished\n");
|
|
reiserfs_close(fs);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* check umounted or read-only mounted filesystems only */
|
|
static void prepare_fs_for_check(reiserfs_filsys_t fs)
|
|
{
|
|
/* The method could be called from auto_check already. */
|
|
if (fs->fs_flags == O_RDWR)
|
|
return;
|
|
|
|
reiserfs_reopen(fs, O_RDWR);
|
|
|
|
fsck_data(fs)->mounted = misc_device_mounted(fs->fs_file_name);
|
|
|
|
if (fsck_data(fs)->mounted > 0) {
|
|
if (fsck_data(fs)->mounted == MF_RW) {
|
|
fsck_progress
|
|
("Partition %s is mounted with write permissions, "
|
|
"cannot check it\n", fs->fs_file_name);
|
|
reiserfs_close(fs);
|
|
exit(EXIT_USER);
|
|
}
|
|
|
|
/* If not CHECK mode, lock the process in the memory. */
|
|
if (fsck_mode(fs) != FSCK_CHECK) {
|
|
if (mlockall(MCL_CURRENT)) {
|
|
reiserfs_exit(EXIT_OPER,
|
|
"Failed to lock the process to "
|
|
"fsck the mounted ro partition. %s.\n",
|
|
strerror(errno));
|
|
}
|
|
}
|
|
|
|
if (fsck_skip_journal(fs)) {
|
|
reiserfs_exit(EXIT_USER, "Jounrnal of the mounted "
|
|
"filesystem must be specified.\n");
|
|
}
|
|
|
|
if (!reiserfs_journal_opened(fs)) {
|
|
/* just to make sure */
|
|
reiserfs_panic("Journal is not opened");
|
|
} else if (reiserfs_journal_params_check(fs)) {
|
|
reiserfs_close(fs);
|
|
exit(EXIT_FATAL);
|
|
}
|
|
|
|
fsck_progress
|
|
("Filesystem seems mounted read-only. Skipping journal "
|
|
"replay.\n");
|
|
} else if (!fsck_skip_journal(fs)) {
|
|
if (reiserfs_journal_params_check(fs)) {
|
|
reiserfs_close(fs);
|
|
exit(EXIT_FATAL);
|
|
}
|
|
|
|
/* filesystem is not mounted, replay journal before checking */
|
|
reiserfsck_replay_journal(fs);
|
|
}
|
|
}
|
|
|
|
static void rebuild_tree(reiserfs_filsys_t fs)
|
|
{
|
|
time_t t;
|
|
int ret;
|
|
|
|
init_rollback_file(state_rollback_file(fs), &fs->fs_blocksize,
|
|
fsck_data(fs)->log);
|
|
|
|
prepare_fs_for_check(fs);
|
|
|
|
ret = reiserfs_open_ondisk_bitmap(fs);
|
|
if (ret < 0) {
|
|
fsck_progress("reiserfsck: Could not open bitmap\n");
|
|
reiserfs_close(fs);
|
|
exit(EXIT_OPER);
|
|
} else if (ret > 0) {
|
|
fsck_log
|
|
("Zero bit found in on-disk bitmap after the last valid bit. "
|
|
"Fixed.\n");
|
|
}
|
|
|
|
time(&t);
|
|
fsck_progress("###########\n"
|
|
"reiserfsck --rebuild-tree started at %s"
|
|
"###########\n", ctime(&t));
|
|
|
|
switch (where_to_start_from(fs)) {
|
|
case START_FROM_THE_BEGINNING:
|
|
reset_super_block(fs);
|
|
pass_0(fs);
|
|
|
|
case START_FROM_PASS_1:
|
|
reset_super_block(fs);
|
|
pass_1(fs);
|
|
|
|
case START_FROM_PASS_2:
|
|
pass_2(fs);
|
|
|
|
case START_FROM_SEMANTIC:
|
|
pass_3_semantic(fs);
|
|
|
|
/* if --lost+found is set - link unaccessed directories to lost+found
|
|
directory */
|
|
case START_FROM_LOST_FOUND:
|
|
pass_3a_look_for_lost(fs);
|
|
|
|
case START_FROM_PASS_4:
|
|
/* 4. look for unaccessed items in the leaves */
|
|
pass_4_check_unaccessed_items();
|
|
|
|
ret = the_end(fs);
|
|
}
|
|
|
|
close_rollback_file();
|
|
|
|
time(&t);
|
|
fsck_progress("###########\n"
|
|
"reiserfsck finished at %s" "###########\n", ctime(&t));
|
|
exit(ret);
|
|
}
|
|
|
|
static void clean_attributes(reiserfs_filsys_t fs)
|
|
{
|
|
time_t t;
|
|
|
|
time(&t);
|
|
|
|
if (get_sb_umount_state(fs->fs_ondisk_sb) != FS_CLEANLY_UMOUNTED) {
|
|
fsck_progress("Filesystem is not clean\n"
|
|
"Check consistency of the partition first.\n");
|
|
exit(EXIT_USER);
|
|
}
|
|
if (get_sb_fs_state(fs->fs_ondisk_sb) != FS_CONSISTENT) {
|
|
fsck_progress("Filesystem seems to be in unconsistent state.\n"
|
|
"Check consistency of the partition first.\n");
|
|
exit(EXIT_USER);
|
|
}
|
|
|
|
if (get_reiserfs_format(fs->fs_ondisk_sb) != REISERFS_FORMAT_3_6) {
|
|
fsck_progress
|
|
("Filesystems of 3_5 format do not support extended "
|
|
"attributes.\n");
|
|
|
|
exit(EXIT_USER);
|
|
}
|
|
fsck_progress("###########\n"
|
|
"reiserfsck --clean-attributes started at %s"
|
|
"###########\n", ctime(&t));
|
|
|
|
init_rollback_file(state_rollback_file(fs), &fs->fs_blocksize,
|
|
fsck_data(fs)->log);
|
|
|
|
prepare_fs_for_check(fs);
|
|
|
|
do_clean_attributes(fs);
|
|
|
|
clean_after_dma_check(fs->fs_dev, &dma_info);
|
|
|
|
fsck_progress("###########\n"
|
|
"reiserfsck finished at %s" "###########\n", ctime(&t));
|
|
reiserfs_close(fs);
|
|
close_rollback_file();
|
|
|
|
exit(EXIT_FIXED);
|
|
|
|
}
|
|
|
|
static int reiserfs_check_auto_state(reiserfs_filsys_t fs)
|
|
{
|
|
time_t now = time(NULL);
|
|
time_t lastcheck = get_sb_v2_lastcheck(fs->fs_ondisk_sb);
|
|
unsigned int mnt_count = get_sb_v2_mnt_count(fs->fs_ondisk_sb);
|
|
unsigned int max_mnt_count = get_sb_v2_max_mnt_count(fs->fs_ondisk_sb);
|
|
unsigned int interval = get_sb_v2_check_interval(fs->fs_ondisk_sb);
|
|
|
|
/* v3.5 file systems don't have the superblock fields for this */
|
|
if (get_sb_version(fs->fs_ondisk_sb) == REISERFS_FORMAT_3_5)
|
|
return 1;
|
|
|
|
if (lastcheck == 0 || mnt_count == 0 || max_mnt_count == 0 ||
|
|
interval == 0) {
|
|
fprintf(stderr, "File system hasn't been enabled for faster "
|
|
"boot-time checking. It will be enabled after a "
|
|
"successful run.\n");
|
|
return 1;
|
|
}
|
|
|
|
if (interval != UINT_MAX && now > lastcheck + interval) {
|
|
fprintf(stderr, "File system hasn't been checked in %lu days. "
|
|
"Checking now.\n", (now - lastcheck) / (60 * 60 * 24));
|
|
return 1;
|
|
}
|
|
|
|
if (interval != UINT_MAX && lastcheck > now) {
|
|
fprintf(stderr, "File system check timestamp is in the future. "
|
|
"Checking now.\n");
|
|
return 1;
|
|
}
|
|
|
|
if (mnt_count > max_mnt_count && max_mnt_count != USHRT_MAX) {
|
|
fprintf(stderr, "File system has been mounted %u times "
|
|
"without being checked. Checking now.\n", mnt_count);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int auto_check(reiserfs_filsys_t fs)
|
|
{
|
|
__u16 state;
|
|
int retval = 0;
|
|
int force = fsck_data(fs)->options & OPT_FORCE;
|
|
|
|
print_super_block(stdout, fs, fs->fs_file_name, fs->fs_super_bh, 1);
|
|
|
|
state = get_sb_fs_state(fs->fs_ondisk_sb);
|
|
if ((state & FS_FATAL) == FS_FATAL) {
|
|
fprintf(stderr,
|
|
"Filesystem seems to have fatal corruptions. Running "
|
|
"with --rebuild-tree is required.\n");
|
|
goto error;
|
|
}
|
|
|
|
if ((state & FS_ERROR) == FS_ERROR) {
|
|
fprintf(stderr,
|
|
"Some corruptions on the filesystem were detected. Switching to "
|
|
"the --fix-fixable mode.\n");
|
|
/* run fixable pass. */
|
|
return 0;
|
|
}
|
|
|
|
if (state != FS_CONSISTENT)
|
|
fprintf(stderr,
|
|
"Some strange state was specified in the super block. "
|
|
"Do usual check.\n");
|
|
|
|
if (get_sb_umount_state(fs->fs_ondisk_sb) == FS_CLEANLY_UMOUNTED &&
|
|
!force && !reiserfs_check_auto_state(fs))
|
|
exit(EXIT_OK);
|
|
prepare_fs_for_check(fs);
|
|
if (!force && !reiserfs_check_auto_state(fs))
|
|
exit(EXIT_OK);
|
|
|
|
/* Check bitmaps. */
|
|
retval = reiserfs_open_ondisk_bitmap(fs);
|
|
|
|
if (retval > 0) {
|
|
fsck_log
|
|
("Zero bit found in on-disk bitmap after the last valid bit. "
|
|
"Switching to --fix-fixable mode.\n");
|
|
/* run fixable pass. */
|
|
return 0;
|
|
} else if (retval < 0) {
|
|
fsck_progress("reiserfsck: Could not open bitmap\n");
|
|
goto error;
|
|
}
|
|
|
|
if (get_sb_block_count(fs->fs_ondisk_sb) -
|
|
get_sb_free_blocks(fs->fs_ondisk_sb) !=
|
|
fs->fs_bitmap2->bm_set_bits) {
|
|
fsck_log
|
|
("Wrong amount of used blocks. Switching to the --fix-fixable mode.\n");
|
|
/* run fixable pass. */
|
|
return 0;
|
|
}
|
|
|
|
check_fs_tree(fs);
|
|
|
|
if (fsck_data(fs)->check.fatal_corruptions) {
|
|
fprintf(stderr,
|
|
"%lu fatal corruption(s) found in the root block. Running "
|
|
"with the --rebuild-tree is required.\n",
|
|
fsck_data(fs)->check.fatal_corruptions);
|
|
goto fatal_error;
|
|
} else if (fsck_data(fs)->check.fixable_corruptions) {
|
|
/* seems that this cannot happen. */
|
|
fprintf(stderr, "%lu fixable corruption(s) found. Switching to "
|
|
"the --fix-fixable mode.\n",
|
|
fsck_data(fs)->check.fixable_corruptions);
|
|
fsck_data(fs)->check.fixable_corruptions = 0;
|
|
/* run fixable pass. */
|
|
return 0;
|
|
}
|
|
|
|
reiserfs_update_interval_fields(fs);
|
|
mark_buffer_dirty(fs->fs_super_bh);
|
|
bwrite(fs->fs_super_bh);
|
|
fs->fs_dirt = 1;
|
|
|
|
clean_after_dma_check(fs->fs_dev, &dma_info);
|
|
|
|
reiserfs_close(fs);
|
|
/* do not do anything else. */
|
|
exit(EXIT_OK);
|
|
|
|
fatal_error:
|
|
set_sb_fs_state(fs->fs_ondisk_sb, FS_FATAL);
|
|
mark_buffer_dirty(fs->fs_super_bh);
|
|
bwrite(fs->fs_super_bh);
|
|
error:
|
|
clean_after_dma_check(fs->fs_dev, &dma_info);
|
|
reiserfs_close(fs);
|
|
exit(EXIT_FATAL);
|
|
}
|
|
|
|
/* check umounted or read-only mounted filesystems only */
|
|
static void check_fs(reiserfs_filsys_t fs)
|
|
{
|
|
int retval = EXIT_OK;
|
|
time_t t;
|
|
|
|
time(&t);
|
|
|
|
if (fsck_mode(fs) != FSCK_FIX_FIXABLE) {
|
|
fsck_progress("###########\n"
|
|
"reiserfsck --check started at %s"
|
|
"###########\n", ctime(&t));
|
|
} else {
|
|
fsck_progress("###########\n"
|
|
"reiserfsck --fix-fixable started at %s"
|
|
"###########\n", ctime(&t));
|
|
}
|
|
|
|
init_rollback_file(state_rollback_file(fs), &fs->fs_blocksize,
|
|
fsck_data(fs)->log);
|
|
|
|
prepare_fs_for_check(fs);
|
|
|
|
if (!fs->fs_bitmap2)
|
|
/* It could be done on auto_check already. */
|
|
retval = reiserfs_open_ondisk_bitmap(fs);
|
|
|
|
if (retval > 0) {
|
|
if (fsck_mode(fs) != FSCK_FIX_FIXABLE) {
|
|
fsck_log
|
|
("Zero bit found in on-disk bitmap after the last valid "
|
|
"bit.\n");
|
|
|
|
one_more_corruption(fs, FIXABLE);
|
|
} else {
|
|
fsck_log
|
|
("Zero bit found in on-disk bitmap after the last valid "
|
|
"bit. Fixed.\n");
|
|
}
|
|
} else if (retval < 0) {
|
|
fsck_progress("reiserfsck: Could not open bitmap\n");
|
|
reiserfs_close(fs);
|
|
exit(EXIT_OPER);
|
|
}
|
|
|
|
check_fs_tree(fs);
|
|
|
|
semantic_check();
|
|
|
|
if (fsck_data(fs)->check.fatal_corruptions) {
|
|
fsck_progress
|
|
("%lu found corruptions can be fixed only when running with "
|
|
"--rebuild-tree\n",
|
|
fsck_data(fs)->check.fatal_corruptions);
|
|
|
|
set_sb_fs_state(fs->fs_ondisk_sb, FS_FATAL);
|
|
mark_buffer_dirty(fs->fs_super_bh);
|
|
retval = EXIT_FATAL;
|
|
} else if (fsck_data(fs)->check.fixable_corruptions) {
|
|
/* fixable corruptions found */
|
|
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
|
|
/* fixable corruptions found and fix-fixable has not fixed them,
|
|
* do rebuild-tree */
|
|
|
|
fsck_progress
|
|
("Fatal error: %lu fixable corruptions found after "
|
|
"--fix-fixable.\n",
|
|
fsck_data(fs)->check.fixable_corruptions);
|
|
retval = EXIT_OPER;
|
|
} else {
|
|
fsck_progress
|
|
("%lu found corruptions can be fixed when running with "
|
|
"--fix-fixable\n",
|
|
fsck_data(fs)->check.fixable_corruptions);
|
|
|
|
retval = EXIT_FIXABLE;
|
|
}
|
|
set_sb_fs_state(fs->fs_ondisk_sb, FS_ERROR);
|
|
mark_buffer_dirty(fs->fs_super_bh);
|
|
} else {
|
|
fsck_progress("No corruptions found\n");
|
|
stage_report(5, fs);
|
|
|
|
if (fsck_mode(fs) != FSCK_CHECK) {
|
|
if (misc_device_mounted(fs->fs_file_name) == MF_RO) {
|
|
reiserfs_warning(stderr,
|
|
"\nThe partition is mounted ro. It is better "
|
|
"to umount and mount it again.\n\n");
|
|
retval = EXIT_REBOOT;
|
|
} else
|
|
retval = EXIT_FIXED;
|
|
} else
|
|
retval = EXIT_OK;
|
|
|
|
mark_filesystem_consistent(fs);
|
|
}
|
|
|
|
if (fsck_mode(fs) == FSCK_FIX_FIXABLE
|
|
&& !fsck_data(fs)->check.fatal_corruptions)
|
|
id_map_flush(proper_id_map(fs), fs);
|
|
|
|
id_map_free(proper_id_map(fs));
|
|
clean_after_dma_check(fs->fs_dev, &dma_info);
|
|
|
|
//clear_relocated_list();
|
|
|
|
time(&t);
|
|
fsck_progress("###########\n"
|
|
"reiserfsck finished at %s" "###########\n", ctime(&t));
|
|
|
|
reiserfs_close(fs);
|
|
close_rollback_file();
|
|
exit(retval);
|
|
}
|
|
|
|
static int open_devices_for_rollback(char *file_name, struct fsck_data *data)
|
|
{
|
|
int fd;
|
|
|
|
fd = open(file_name, O_RDWR | O_LARGEFILE);
|
|
|
|
if (fd == -1) {
|
|
reiserfs_warning(stderr, "reiserfsck: Cannot not open the fs "
|
|
"partition %s\n", file_name);
|
|
|
|
return -1;
|
|
}
|
|
|
|
fs = getmem(sizeof(*fs));
|
|
fs->fs_dev = fd;
|
|
fs->fs_vp = data;
|
|
asprintf(&fs->fs_file_name, "%s", file_name);
|
|
|
|
if (data->journal_dev_name && strcmp(data->journal_dev_name, file_name)) {
|
|
fs->fs_journal_dev = open(data->journal_dev_name,
|
|
O_RDWR | O_LARGEFILE);
|
|
if (fs->fs_journal_dev == -1) {
|
|
reiserfs_warning(stderr,
|
|
"Cannot open journal partition\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (open_rollback_file(state_rollback_file(fs), fsck_data(fs)->log))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void fsck_rollback(reiserfs_filsys_t fs)
|
|
{
|
|
time_t t;
|
|
|
|
time(&t);
|
|
fsck_progress("###########\n"
|
|
"reiserfsck --rollback-fsck-changes started at %s"
|
|
"###########\n", ctime(&t));
|
|
|
|
do_fsck_rollback(fs->fs_dev, fs->fs_journal_dev,
|
|
fsck_progress_file(fs));
|
|
close_rollback_file();
|
|
|
|
close(fs->fs_journal_dev);
|
|
free(fs->fs_file_name);
|
|
fs->fs_file_name = NULL;
|
|
close(fs->fs_dev);
|
|
freemem(fs);
|
|
|
|
time(&t);
|
|
fsck_progress("###########\n"
|
|
"reiserfsck finished at %s" "###########\n", ctime(&t));
|
|
|
|
exit(EXIT_FIXED);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char *file_name;
|
|
struct fsck_data *data;
|
|
struct rlimit rlim = { RLIM_INFINITY, RLIM_INFINITY };
|
|
char *width;
|
|
int retval;
|
|
long error;
|
|
|
|
width = getenv("COLUMNS");
|
|
if (width)
|
|
screen_width = atoi(width);
|
|
|
|
if (screen_width == 0)
|
|
screen_width = 80; // We default to 80 characters wide screen
|
|
screen_width--;
|
|
screen_savebuffer_len = screen_width;
|
|
screen_savebuffer = getmem(screen_width + 1);
|
|
memset(screen_savebuffer, 0, screen_savebuffer_len + 1);
|
|
|
|
/* this is only needed (and works) when running under 2.4 on regular files */
|
|
if (setrlimit(RLIMIT_FSIZE, &rlim) == -1) {
|
|
reiserfs_warning(stderr,
|
|
"Cannot change the system limit for file size "
|
|
"with setrlimit: %s\n", strerror(errno));
|
|
}
|
|
|
|
data = getmem(sizeof(struct fsck_data));
|
|
|
|
file_name = parse_options(data, argc, argv);
|
|
|
|
if (data->mode != FSCK_AUTO)
|
|
print_banner("reiserfsck");
|
|
|
|
if (data->mode == DO_NOTHING) {
|
|
freemem(data);
|
|
exit(EXIT_OK);
|
|
}
|
|
|
|
if (data->options & OPT_BACKGROUND) {
|
|
/* running in background reiserfsck appends progress information into
|
|
'fsck.run'. Logs get there if log file was not specified */
|
|
data->options |= OPT_QUIET;
|
|
data->progress = fopen("fsck.run", "a+");
|
|
if (!data->progress) {
|
|
reiserfs_exit(EXIT_OPER,
|
|
"reiserfsck: Cannot not open \"fsck.run\"");
|
|
}
|
|
|
|
if (data->log == stdout)
|
|
/* no log file specifed - redirect log into 'fsck.run' */
|
|
data->log = data->progress;
|
|
|
|
retval = fork();
|
|
if (retval == -1) {
|
|
reiserfs_panic("reiserfsck: Fork failed: %s",
|
|
strerror(errno));
|
|
} else if (retval != 0) {
|
|
exit(EXIT_OPER);
|
|
}
|
|
reiserfs_warning(stderr,
|
|
"\nReiserfsck is running in background as "
|
|
"[%d],\nmake sure that it gets all the confirmations from stdin "
|
|
"that it requests.\n\n", getpid());
|
|
}
|
|
|
|
/* This asks for confirmation also. */
|
|
if (data->mode != FSCK_AUTO)
|
|
warn_what_will_be_done(file_name, data);
|
|
|
|
if (data->mode == FSCK_ROLLBACK_CHANGES) {
|
|
if (open_devices_for_rollback(file_name, data) == -1)
|
|
exit(EXIT_OPER);
|
|
} else {
|
|
fs = reiserfs_open(file_name, O_RDONLY, &error, data,
|
|
data->mode != FSCK_SB);
|
|
|
|
if (error) {
|
|
reiserfs_exit(EXIT_OPER, "Failed to open the device "
|
|
"'%s': %s\n\n", file_name,
|
|
error_message(error));
|
|
}
|
|
|
|
if (data->mode != FSCK_SB) {
|
|
if (no_reiserfs_found(fs)) {
|
|
reiserfs_exit(EXIT_OPER,
|
|
"Failed to open the filesystem.\n\n"
|
|
"If the partition table has not been changed, "
|
|
"and the partition is\nvalid and it really "
|
|
"contains a reiserfs partition, then the\n"
|
|
"superblock is corrupted and you need to run "
|
|
"this utility with\n--rebuild-sb.\n");
|
|
}
|
|
if (fsck_skip_journal(fs) &&
|
|
!is_reiserfs_jr_magic_string(fs->fs_ondisk_sb)) {
|
|
reiserfs_warning(stderr,
|
|
"Filesystem with default journal found, "
|
|
"--no-journal-available is ignored\n");
|
|
fsck_data(fs)->options &= ~OPT_SKIP_JOURNAL;
|
|
}
|
|
|
|
if (!fsck_skip_journal(fs)) {
|
|
retval =
|
|
reiserfs_open_journal(fs,
|
|
data->
|
|
journal_dev_name,
|
|
O_RDONLY);
|
|
|
|
if (retval) {
|
|
fsck_progress
|
|
("Failed to open the journal device (%s).\n",
|
|
data->journal_dev_name);
|
|
|
|
if (retval == 1) {
|
|
fsck_progress
|
|
("Run --rebuild-sb to rebuild journal parameters.\n");
|
|
}
|
|
|
|
reiserfs_close(fs);
|
|
exit(EXIT_OPER);
|
|
}
|
|
}
|
|
|
|
if (data->options & BADBLOCKS_FILE) {
|
|
if (create_badblock_bitmap(fs, badblocks_file)
|
|
!= 0)
|
|
exit(EXIT_OPER);
|
|
}
|
|
|
|
register_timer();
|
|
}
|
|
}
|
|
|
|
switch (data->mode) {
|
|
case FSCK_SB:
|
|
rebuild_sb(fs, file_name, data);
|
|
break;
|
|
|
|
case FSCK_AUTO:
|
|
/* perform some light-weight checks. If error, do fixable job. */
|
|
if (auto_check(fs))
|
|
break;
|
|
data->mode = FSCK_FIX_FIXABLE;
|
|
case FSCK_CHECK:
|
|
case FSCK_FIX_FIXABLE:
|
|
check_fs(fs);
|
|
break;
|
|
|
|
case FSCK_REBUILD:
|
|
case DO_TEST:
|
|
rebuild_tree(fs);
|
|
break;
|
|
|
|
case FSCK_ROLLBACK_CHANGES:
|
|
fsck_rollback(fs);
|
|
break;
|
|
case FSCK_CLEAN_ATTRIBUTES:
|
|
clean_attributes(fs);
|
|
}
|
|
|
|
exit(EXIT_OPER);
|
|
}
|