e2fsprogs/e2fsck/unix.c
Theodore Ts'o 5596defa1e Many files:
unix.c: Add support for calculating a progress bar if the -C0 option
  	is given.  The function e2fsck_clear_progbar() clears the progress bar
  	and must be called before any message is issued.  SIGUSR1 will enable
  	the progress bar, and SIGUSR2 will disable the progress bar.  This is
  	used by fsck to handle parallel filesystem checks.  Also, set the
  	device_name from the filesystem label if it is available.
  e2fsck.h: Add new flags E2F_FLAG_PROG_BAR and E2F_FLAG_PROG_SUPRESS.
  	Add new field in the e2fsck structure which contains the last tenth of
  	a percent printed for the user.
  message.c (print_e2fsck_message): Add call to e2fsck_clear_progbar().
  pass1.c (e2fsck_pass1):
  pass2.c (e2fsck_pass2):
  pass3.c (e2fsck_pass3):
  pass4.c (e2fsck_pass4):
  pass5.c (e2fsck_pass5): Add call to e2fsck_clear_progbar when printing
  	the resource tracking information.
  pass5.c (check_block_bitmaps, check_inode_bitmaps): If there is an
  	error in the bitmaps, suppress printing the progress bar using the
  	suppression flag for the remainder of the check, in order to clean up
  	the display.
1999-07-19 15:27:37 +00:00

821 lines
20 KiB
C

/*
* unix.c - The unix-specific code for e2fsck
*
* Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <time.h>
#include <signal.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <unistd.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <sys/ioctl.h>
#include <malloc.h>
#include "et/com_err.h"
#include "e2fsck.h"
#include "problem.h"
#include "../version.h"
extern int isatty(int);
/* Command line options */
static int blocksize = 0;
static int swapfs = 0;
static int normalize_swapfs = 0;
static int cflag = 0; /* check disk */
static int show_version_only = 0;
static int force = 0;
static int verbose = 0;
static int replace_bad_blocks = 0;
static char *bad_blocks_file = 0;
static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
static int root_filesystem = 0;
static int read_only_root = 0;
static void usage(e2fsck_t ctx)
{
fprintf(stderr,
"Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n"
"\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
"\t\t[-l|-L bad_blocks_file] [-C fd] device\n",
ctx->program_name);
exit(FSCK_USAGE);
}
static void show_stats(e2fsck_t ctx)
{
ext2_filsys fs = ctx->fs;
int inodes, inodes_used, blocks, blocks_used;
int dir_links;
int num_files, num_links;
int frag_percent;
dir_links = 2 * ctx->fs_directory_count - 1;
num_files = ctx->fs_total_count - dir_links;
num_links = ctx->fs_links_count - dir_links;
inodes = fs->super->s_inodes_count;
inodes_used = (fs->super->s_inodes_count -
fs->super->s_free_inodes_count);
blocks = fs->super->s_blocks_count;
blocks_used = (fs->super->s_blocks_count -
fs->super->s_free_blocks_count);
frag_percent = (10000 * ctx->fs_fragmented) / inodes_used;
frag_percent = (frag_percent + 5) / 10;
if (!verbose) {
printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
ctx->device_name, inodes_used, inodes,
frag_percent / 10, frag_percent % 10,
blocks_used, blocks);
return;
}
printf ("\n%8d inode%s used (%d%%)\n", inodes_used,
(inodes_used != 1) ? "s" : "",
100 * inodes_used / inodes);
printf ("%8d non-contiguous inodes (%0d.%d%%)\n",
ctx->fs_fragmented, frag_percent / 10, frag_percent % 10);
printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n",
ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
printf ("%8d block%s used (%d%%)\n"
"%8d bad block%s\n", blocks_used,
(blocks_used != 1) ? "s" : "",
100 * blocks_used / blocks, ctx->fs_badblocks_count,
ctx->fs_badblocks_count != 1 ? "s" : "");
printf ("\n%8d regular file%s\n"
"%8d director%s\n"
"%8d character device file%s\n"
"%8d block device file%s\n"
"%8d fifo%s\n"
"%8d link%s\n"
"%8d symbolic link%s (%d fast symbolic link%s)\n"
"%8d socket%s\n"
"--------\n"
"%8d file%s\n",
ctx->fs_regular_count,
(ctx->fs_regular_count != 1) ? "s" : "",
ctx->fs_directory_count,
(ctx->fs_directory_count != 1) ? "ies" : "y",
ctx->fs_chardev_count,
(ctx->fs_chardev_count != 1) ? "s" : "",
ctx->fs_blockdev_count,
(ctx->fs_blockdev_count != 1) ? "s" : "",
ctx->fs_fifo_count,
(ctx->fs_fifo_count != 1) ? "s" : "",
ctx->fs_links_count - dir_links,
((ctx->fs_links_count - dir_links) != 1) ? "s" : "",
ctx->fs_symlinks_count,
(ctx->fs_symlinks_count != 1) ? "s" : "",
ctx->fs_fast_symlinks_count,
(ctx->fs_fast_symlinks_count != 1) ? "s" : "",
ctx->fs_sockets_count, (ctx->fs_sockets_count != 1) ? "s" : "",
ctx->fs_total_count - dir_links,
((ctx->fs_total_count - dir_links) != 1) ? "s" : "");
}
static void check_mount(e2fsck_t ctx)
{
errcode_t retval;
int mount_flags, cont, fd;
retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
if (retval) {
com_err("ext2fs_check_if_mount", retval,
"while determining whether %s is mounted.",
ctx->filesystem_name);
return;
}
if (!(mount_flags & EXT2_MF_MOUNTED))
return;
#if (defined(__linux__) && defined(HAVE_MNTENT_H))
/*
* If the root is mounted read-only, then /etc/mtab is
* probably not correct; so we won't issue a warning based on
* it.
*/
fd = open(MOUNTED, O_RDWR);
if (fd < 0) {
if (errno == EROFS)
return;
} else
close(fd);
#endif
if (ctx->options & E2F_OPT_READONLY) {
printf("Warning! %s is mounted.\n", ctx->filesystem_name);
return;
}
printf("%s is mounted. ", ctx->filesystem_name);
if (!isatty(0) || !isatty(1)) {
printf("Cannot continue, aborting.\n\n");
exit(FSCK_ERROR);
}
printf("\n\n\007\007\007\007WARNING!!! "
"Running e2fsck on a mounted filesystem may cause\n"
"SEVERE filesystem damage.\007\007\007\n\n");
cont = ask_yn("Do you really want to continue", -1);
if (!cont) {
printf ("check aborted.\n");
exit (0);
}
return;
}
/*
* This routine checks to see if a filesystem can be skipped; if so,
* it will exit with E2FSCK_OK. Under some conditions it will print a
* message explaining why a check is being forced.
*/
static void check_if_skip(e2fsck_t ctx)
{
ext2_filsys fs = ctx->fs;
const char *reason = NULL;
if (force || bad_blocks_file || cflag || swapfs)
return;
if (fs->super->s_state & EXT2_ERROR_FS)
reason = "contains a file system with errors";
else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
reason = "was not cleanly unmounted";
else if (fs->super->s_mnt_count >=
(unsigned) fs->super->s_max_mnt_count)
reason = "has reached maximal mount count";
else if (fs->super->s_checkinterval &&
time(0) >= (fs->super->s_lastcheck +
fs->super->s_checkinterval))
reason = "has gone too long without being checked";
if (reason) {
printf("%s %s, check forced.\n", ctx->device_name, reason);
return;
}
printf("%s: clean, %d/%d files, %d/%d blocks\n", ctx->device_name,
fs->super->s_inodes_count - fs->super->s_free_inodes_count,
fs->super->s_inodes_count,
fs->super->s_blocks_count - fs->super->s_free_blocks_count,
fs->super->s_blocks_count);
ext2fs_close(fs);
exit(FSCK_OK);
}
/*
* For completion notice
*/
struct percent_tbl {
int max_pass;
int table[32];
};
struct percent_tbl e2fsck_tbl = {
5, { 0, 70, 90, 92, 95, 100 }
};
static int dpywidth = 50;
static char bar[] =
"==============================================================="
"===============================================================";
static char spaces[] =
" "
" ";
static float calc_percent(struct percent_tbl *tbl, int pass, int curr,
int max)
{
float percent;
if (pass <= 0)
return 0.0;
if (pass > tbl->max_pass)
return 100.0;
percent = ((float) curr) / ((float) max);
return ((percent * (tbl->table[pass] - tbl->table[pass-1]))
+ tbl->table[pass-1]);
}
extern void e2fsck_clear_progbar(e2fsck_t ctx)
{
if (!(ctx->flags & E2F_FLAG_PROG_BAR))
return;
printf("%s\r", spaces + (sizeof(spaces) - 80));
ctx->flags &= ~E2F_FLAG_PROG_BAR;
}
static int e2fsck_update_progress(e2fsck_t ctx, int pass,
unsigned long cur, unsigned long max)
{
const char spinner[] = "\\|/-";
char buf[80];
int i;
float percent;
if (pass == 0)
return 0;
if (ctx->progress_fd) {
sprintf(buf, "%d %lu %lu\n", pass, cur, max);
write(ctx->progress_fd, buf, strlen(buf));
} else {
if (ctx->flags & E2F_FLAG_PROG_SUPPRESS)
return 0;
ctx->progress_pos = (ctx->progress_pos+1) & 3;
ctx->flags |= E2F_FLAG_PROG_BAR;
percent = calc_percent(&e2fsck_tbl, pass, cur, max);
if (ctx->progress_last_percent == (int) 1000 * percent)
return 0;
ctx->progress_last_percent = (int) 1000 * percent;
i = ((percent * dpywidth) + 50) / 100;
printf("%s: |%s%s", ctx->device_name,
bar + (sizeof(bar) - (i+1)),
spaces + (sizeof(spaces) - (dpywidth - i + 1)));
if (percent == 100.0)
fputc('|', stdout);
else
fputc(spinner[ctx->progress_pos & 3], stdout);
printf(" %4.1f%% \r", percent);
if (percent == 100.0)
e2fsck_clear_progbar(ctx);
fflush(stdout);
}
return 0;
}
#define PATH_SET "PATH=/sbin"
static void reserve_stdio_fds(NOARGS)
{
int fd;
while (1) {
fd = open("/dev/null", O_RDWR);
if (fd > 2)
break;
if (fd < 0) {
fprintf(stderr, "ERROR: Couldn't open "
"/dev/null (%s)\n",
strerror(errno));
break;
}
}
close(fd);
}
static e2fsck_t global_signal_ctx;
static void signal_progress_on(int sig)
{
e2fsck_t ctx = global_signal_ctx;
if (!ctx)
return;
ctx->progress = e2fsck_update_progress;
ctx->progress_fd = 0;
}
static void signal_progress_off(int sig)
{
e2fsck_t ctx = global_signal_ctx;
if (!ctx)
return;
e2fsck_clear_progbar(ctx);
ctx->progress = 0;
}
static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
{
int flush = 0;
int c;
#ifdef MTRACE
extern void *mallwatch;
#endif
char *oldpath = getenv("PATH");
e2fsck_t ctx;
errcode_t retval;
struct sigaction sa;
retval = e2fsck_allocate_context(&ctx);
if (retval)
return retval;
*ret_ctx = ctx;
/* Update our PATH to include /sbin */
if (oldpath) {
char *newpath;
newpath = (char *) malloc(sizeof (PATH_SET) + 1 +
strlen (oldpath));
if (!newpath)
fatal_error(ctx, "Couldn't malloc() newpath");
strcpy (newpath, PATH_SET);
strcat (newpath, ":");
strcat (newpath, oldpath);
putenv (newpath);
} else
putenv (PATH_SET);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
initialize_ext2_error_table();
if (argc && *argv)
ctx->program_name = *argv;
else
ctx->program_name = "e2fsck";
while ((c = getopt (argc, argv, "panyrcC:B:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF)
switch (c) {
case 'C':
ctx->progress = e2fsck_update_progress;
ctx->progress_fd = atoi(optarg);
break;
case 'p':
case 'a':
ctx->options |= E2F_OPT_PREEN;
ctx->options &= ~(E2F_OPT_YES|E2F_OPT_NO);
break;
case 'n':
ctx->options |= E2F_OPT_NO;
ctx->options &= ~(E2F_OPT_YES|E2F_OPT_PREEN);
break;
case 'y':
ctx->options |= E2F_OPT_YES;
ctx->options &= ~(E2F_OPT_PREEN|E2F_OPT_NO);
break;
case 't':
#ifdef RESOURCE_TRACK
if (ctx->options & E2F_OPT_TIME)
ctx->options |= E2F_OPT_TIME2;
else
ctx->options |= E2F_OPT_TIME;
#else
fprintf(stderr, "The -t option is not "
"supported on this version of e2fsck.\n");
#endif
break;
case 'c':
cflag++;
ctx->options |= E2F_OPT_CHECKBLOCKS;
break;
case 'r':
/* What we do by default, anyway! */
break;
case 'b':
ctx->use_superblock = atoi(optarg);
break;
case 'B':
blocksize = atoi(optarg);
break;
case 'I':
ctx->inode_buffer_blocks = atoi(optarg);
break;
case 'P':
ctx->process_inode_size = atoi(optarg);
break;
case 'L':
replace_bad_blocks++;
case 'l':
bad_blocks_file = (char *) malloc(strlen(optarg)+1);
if (!bad_blocks_file)
fatal_error(ctx,
"Couldn't malloc bad_blocks_file");
strcpy(bad_blocks_file, optarg);
break;
case 'd':
ctx->options |= E2F_OPT_DEBUG;
break;
case 'f':
force = 1;
break;
case 'F':
#ifdef BLKFLSBUF
flush = 1;
#else
fatal_error(ctx, "-F not supported");
#endif
break;
case 'v':
verbose = 1;
break;
case 'V':
show_version_only = 1;
break;
#ifdef MTRACE
case 'M':
mallwatch = (void *) strtol(optarg, NULL, 0);
break;
#endif
case 'N':
ctx->device_name = optarg;
break;
case 's':
normalize_swapfs = 1;
case 'S':
swapfs = 1;
break;
default:
usage(ctx);
}
if (show_version_only)
return 0;
if (optind != argc - 1)
usage(ctx);
if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
!cflag && !swapfs)
ctx->options |= E2F_OPT_READONLY;
ctx->filesystem_name = argv[optind];
if (flush) {
#ifdef BLKFLSBUF
int fd = open(ctx->filesystem_name, O_RDONLY, 0);
if (fd < 0) {
com_err("open", errno, "while opening %s for flushing",
ctx->filesystem_name);
exit(FSCK_ERROR);
}
if (ioctl(fd, BLKFLSBUF, 0) < 0) {
com_err("BLKFLSBUF", errno, "while trying to flush %s",
ctx->filesystem_name);
exit(FSCK_ERROR);
}
close(fd);
#else
fatal_error(ctx, "BLKFLSBUF not supported");
#endif /* BLKFLSBUF */
}
if (swapfs) {
if (cflag || bad_blocks_file) {
fprintf(stderr, "Incompatible options not "
"allowed when byte-swapping.\n");
exit(FSCK_ERROR);
}
}
/*
* Set up signal action
*/
memset(&sa, 0, sizeof(struct sigaction));
#ifdef SA_RESTART
sa.sa_flags = SA_RESTART;
#endif
global_signal_ctx = ctx;
sa.sa_handler = signal_progress_on;
sigaction(SIGUSR1, &sa, 0);
sa.sa_handler = signal_progress_off;
sigaction(SIGUSR2, &sa, 0);
return 0;
}
static const char *my_ver_string = E2FSPROGS_VERSION;
static const char *my_ver_date = E2FSPROGS_DATE;
int main (int argc, char *argv[])
{
errcode_t retval = 0;
int exit_value = FSCK_OK;
int i;
ext2_filsys fs = 0;
io_manager io_ptr;
struct ext2fs_sb *s;
const char *lib_ver_date;
int my_ver, lib_ver;
e2fsck_t ctx;
struct problem_context pctx;
int flags, run_result;
clear_problem_context(&pctx);
#ifdef MTRACE
mtrace();
#endif
#ifdef MCHECK
mcheck(0);
#endif
my_ver = ext2fs_parse_version_string(my_ver_string);
lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
if (my_ver > lib_ver) {
fprintf( stderr, "Error: ext2fs library version "
"out of date!\n");
show_version_only++;
}
retval = PRS(argc, argv, &ctx);
if (retval) {
com_err("e2fsck", retval,
"while trying to initialize program");
exit(1);
}
reserve_stdio_fds();
#ifdef RESOURCE_TRACK
init_resource_track(&ctx->global_rtrack);
#endif
if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
my_ver_string, my_ver_date, EXT2FS_VERSION,
EXT2FS_DATE);
if (show_version_only) {
fprintf(stderr, "\tUsing %s, %s\n",
error_message(EXT2_ET_BASE), lib_ver_date);
exit(0);
}
check_mount(ctx);
if (!(ctx->options & E2F_OPT_PREEN) &&
!(ctx->options & E2F_OPT_NO) &&
!(ctx->options & E2F_OPT_YES)) {
if (!isatty (0) || !isatty (1))
fatal_error(ctx,
"need terminal for interactive repairs");
}
ctx->superblock = ctx->use_superblock;
restart:
#if 1
io_ptr = unix_io_manager;
#else
io_ptr = test_io_manager;
test_io_backing_manager = unix_io_manager;
#endif
flags = (ctx->options & E2F_OPT_READONLY) ? 0 : EXT2_FLAG_RW;
if (ctx->superblock && blocksize) {
retval = ext2fs_open(ctx->filesystem_name, flags,
ctx->superblock, blocksize, io_ptr, &fs);
} else if (ctx->superblock) {
for (i=0; possible_block_sizes[i]; i++) {
retval = ext2fs_open(ctx->filesystem_name, flags,
ctx->superblock,
possible_block_sizes[i],
io_ptr, &fs);
if (!retval)
break;
}
} else
retval = ext2fs_open(ctx->filesystem_name, flags,
0, 0, io_ptr, &fs);
if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
((retval == EXT2_ET_BAD_MAGIC) ||
((retval == 0) && ext2fs_check_desc(fs)))) {
if (!fs || (fs->group_desc_count > 1)) {
printf("%s trying backup blocks...\n",
retval ? "Couldn't find ext2 superblock," :
"Group descriptors look bad...");
ctx->superblock = get_backup_sb(fs);
if (fs)
ext2fs_close(fs);
goto restart;
}
}
if (retval) {
com_err(ctx->program_name, retval, "while trying to open %s",
ctx->filesystem_name);
if (retval == EXT2_ET_REV_TOO_HIGH) {
printf("The filesystem revision is apparently "
"too high for this version of e2fsck.\n"
"(Or the filesystem superblock "
"is corrupt)\n\n");
fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
} else if (retval == EXT2_ET_SHORT_READ)
printf("Could this be a zero-length partition?\n");
else if ((retval == EPERM) || (retval == EACCES))
printf("You must have %s access to the "
"filesystem or be root\n",
(ctx->options & E2F_OPT_READONLY) ?
"r/o" : "r/w");
else if (retval == ENXIO)
printf("Possibly non-existent or swap device?\n");
#ifdef EROFS
else if (retval == EROFS)
printf("Disk write-protected; use the -n option "
"to do a read-only\n"
"check of the device.\n");
#endif
else
fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
exit(FSCK_ERROR);
}
ctx->fs = fs;
fs->priv_data = ctx;
#ifdef EXT2_CURRENT_REV
if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH,
"while trying to open %s",
ctx->filesystem_name);
get_newer:
fatal_error(ctx, "Get a newer version of e2fsck!");
}
#endif
/*
* Check for compatibility with the feature sets. We need to
* be more stringent than ext2fs_open().
*/
s = (struct ext2fs_sb *) fs->super;
if ((s->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
(s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
"(%s)", ctx->filesystem_name);
goto get_newer;
}
if (s->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE,
"(%s)", ctx->filesystem_name);
goto get_newer;
}
if (ctx->device_name == 0 &&
(s->s_volume_name[0] != 0)) {
char *cp = malloc(sizeof(s->s_volume_name)+1);
if (cp) {
strncpy(cp, s->s_volume_name,
sizeof(s->s_volume_name));
cp[sizeof(s->s_volume_name)] = 0;
ctx->device_name = cp;
}
}
if (ctx->device_name == 0)
ctx->device_name = ctx->filesystem_name;
/*
* If the user specified a specific superblock, presumably the
* master superblock has been trashed. So we mark the
* superblock as dirty, so it can be written out.
*/
if (ctx->superblock &&
!(ctx->options & E2F_OPT_READONLY))
ext2fs_mark_super_dirty(fs);
/*
* Don't overwrite the backup superblock and block
* descriptors, until we're sure the filesystem is OK....
*/
fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
ehandler_init(fs->io);
if (ctx->superblock)
set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0);
check_super_block(ctx);
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
exit(FSCK_ERROR);
check_if_skip(ctx);
if (bad_blocks_file)
read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks);
else if (cflag)
test_disk(ctx);
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
exit(FSCK_ERROR);
if (normalize_swapfs) {
if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ==
ext2fs_native_flag()) {
fprintf(stderr, "%s: Filesystem byte order "
"already normalized.\n", ctx->device_name);
exit(FSCK_ERROR);
}
}
if (swapfs) {
swap_filesys(ctx);
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
exit(FSCK_ERROR);
}
/*
* Mark the system as valid, 'til proven otherwise
*/
ext2fs_mark_valid(fs);
retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
if (retval) {
com_err(ctx->program_name, retval,
"while reading bad blocks inode");
preenhalt(ctx);
printf("This doesn't bode well, but we'll try to go on...\n");
}
run_result = e2fsck_run(ctx);
e2fsck_clear_progbar(ctx);
if (run_result == E2F_FLAG_RESTART) {
printf("Restarting e2fsck from the beginning...\n");
retval = e2fsck_reset_context(ctx);
if (retval) {
com_err(ctx->program_name, retval,
"while resetting context");
exit(1);
}
ext2fs_close(fs);
goto restart;
}
if (run_result & E2F_FLAG_SIGNAL_MASK)
exit(FSCK_ERROR);
if (run_result & E2F_FLAG_CANCEL)
ext2fs_unmark_valid(fs);
#ifdef MTRACE
mtrace_print("Cleanup");
#endif
if (ext2fs_test_changed(fs)) {
exit_value = FSCK_NONDESTRUCT;
if (!(ctx->options & E2F_OPT_PREEN))
printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
ctx->device_name);
if (root_filesystem && !read_only_root) {
printf("%s: ***** REBOOT LINUX *****\n",
ctx->device_name);
exit_value = FSCK_REBOOT;
}
}
if (ext2fs_test_valid(fs))
fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
else
exit_value = FSCK_UNCORRECTED;
if (!(ctx->options & E2F_OPT_READONLY)) {
if (ext2fs_test_valid(fs)) {
if (!(fs->super->s_state & EXT2_VALID_FS))
exit_value = FSCK_NONDESTRUCT;
fs->super->s_state = EXT2_VALID_FS;
} else
fs->super->s_state &= ~EXT2_VALID_FS;
fs->super->s_mnt_count = 0;
fs->super->s_lastcheck = time(NULL);
ext2fs_mark_super_dirty(fs);
}
show_stats(ctx);
e2fsck_write_bitmaps(ctx);
#ifdef RESOURCE_TRACK
if (ctx->options & E2F_OPT_TIME)
print_resource_track(NULL, &ctx->global_rtrack);
#endif
e2fsck_free_context(ctx);
ext2fs_close(fs);
return exit_value;
}