While Namesys drove almost all reiserfs development and was instrumental in supporting it for many years, it has been offline for the past 6 years. All of its founders and employees have moved on to other endeavors or are otherwise unavailable. This can be confusing to users since the documentation points there either for background information or to have bugs fixed. This patch removes most of the non-historical references to namesys.com and directs users to the reiserfs-devel list on vger. Signed-off-by: Jeff Mahoney <jeffm@suse.com>
1374 lines
41 KiB
C
1374 lines
41 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;
|
|
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, 0, 'l'},
|
|
{"badblocks", required_argument, 0, 'B'},
|
|
{"interactive", no_argument, 0, 'i'},
|
|
{"adjust-size", no_argument, 0, 'z'},
|
|
{"quiet", no_argument, 0, 'q'},
|
|
{"yes", no_argument, 0, 'y'},
|
|
{"force", no_argument, 0, 'f'},
|
|
{"nolog", no_argument, 0, '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, 0, 'b'},
|
|
|
|
{"create-passes-dump", required_argument, 0, 'd'},
|
|
|
|
/* all blocks will be read */
|
|
{"scan-whole-partition", no_argument, 0, 'S'},
|
|
/* useful for -S */
|
|
{"hash", required_argument, 0, 'h'},
|
|
|
|
/* preparing rollback data*/
|
|
{"rollback-data", required_argument, 0, 'R'},
|
|
|
|
{"journal", required_argument, 0, 'j'},
|
|
{"no-journal-available", no_argument, &flag, OPT_SKIP_JOURNAL},
|
|
|
|
{"bad-block-file", required_argument, 0, 'B'},
|
|
|
|
/* start reiserfsck in background and exit */
|
|
{"background", no_argument, 0, 'g'},
|
|
|
|
{0, 0, 0, 0}
|
|
};
|
|
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) == 0)
|
|
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"
|
|
|
|
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;
|
|
|
|
void check_dma() {
|
|
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);
|
|
}
|
|
|
|
void register_timer() {
|
|
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 = 0;
|
|
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 == 0) {
|
|
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);
|
|
|
|
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 = 0;
|
|
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;
|
|
int 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);
|
|
|
|
lost_found_dir_key.k2_dir_id = cpu_to_le32(lost_found_dir_key.k2_dir_id);
|
|
lost_found_dir_key.k2_objectid = cpu_to_le32(lost_found_dir_key.k2_objectid);
|
|
/* 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, strerror(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);
|
|
}
|
|
|