Many files:
pass*.c, super.c: Massive changes to avoid using printf and com_err
routines. All diagnostic messages are now routed through the
fix_problem interface.
pass2.c (check_dir_block): Check for duplicate '.' and '..' entries.
problem.c, problem.h: Add new problem codes PR_2_DUP_DOT and
PR_2_DUP_DOT_DOT.
problem.c: Added new problem codes for some of the superblock
corruption checks, and for the pass header messages. ("Pass
1: xxxxx")
util.c (print_resource_track): Now takes a description argument.
super.c, unix.c, e2fsck.c: New files to separate out the
operating-specific operations out from e2fsck.c. e2fsck.c now
contains the global e2fsck context management routines, and
super.c contains the "pass 0" initial validation of the
superblock and global block group descriptors.
pass1.c, pass2.c, pass3.c, pass4.c, pass5.c, util.c: Eliminate
(nearly) all global variables and moved them to the e2fsck
context structure.
problem.c, problem.h: Added new problem codes PR_0_SB_CORRUPT,
PR_0_FS_SIZE_WRONG, PR_0_NO_FRAGMENTS, PR_0_BLOCKS_PER_GROUP,
PR_0_FIRST_DATA_BLOCK
expect.1, expect.2:
Updated tests to align with e2fsck problem.c changes.
1997-10-03 21:48:10 +04:00
|
|
|
/*
|
|
|
|
* 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>
|
|
|
|
#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;
|
|
|
|
|
|
|
|
int restart_e2fsck = 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] 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->device_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("%s is mounted.\n\n", ctx->device_name);
|
|
|
|
printf("\a\a\a\aWARNING!!! Running e2fsck on a mounted filesystem "
|
|
|
|
"may cause\nSEVERE filesystem damage.\a\a\a\n\n");
|
|
|
|
if (isatty (0) && isatty (1))
|
|
|
|
cont = ask_yn("Do you really want to continue", -1);
|
|
|
|
else
|
|
|
|
cont = 0;
|
|
|
|
if (!cont) {
|
|
|
|
printf ("check aborted.\n");
|
|
|
|
exit (0);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sync_disks(NOARGS)
|
|
|
|
{
|
|
|
|
sync();
|
|
|
|
sync();
|
|
|
|
sleep(1);
|
|
|
|
sync();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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_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";
|
|
|
|
else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
|
|
|
|
reason = "was not cleanly unmounted";
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define PATH_SET "PATH=/sbin"
|
|
|
|
|
|
|
|
static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
|
|
|
|
{
|
|
|
|
int flush = 0;
|
|
|
|
char c;
|
|
|
|
#ifdef MTRACE
|
|
|
|
extern void *mallwatch;
|
|
|
|
#endif
|
|
|
|
char *oldpath = getenv("PATH");
|
|
|
|
e2fsck_t ctx;
|
|
|
|
errcode_t retval;
|
|
|
|
|
|
|
|
retval = e2fsck_allocate_context(&ctx);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
*ret_ctx = ctx;
|
|
|
|
|
|
|
|
/* Update our PATH to include /sbin */
|
|
|
|
if (oldpath) {
|
|
|
|
char *newpath;
|
|
|
|
|
|
|
|
newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
|
|
|
|
if (!newpath)
|
|
|
|
fatal_error("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, "panyrcB:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF)
|
|
|
|
switch (c) {
|
|
|
|
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':
|
1997-10-20 05:38:32 +04:00
|
|
|
#ifdef RESOURCE_TRACK
|
Many files:
pass*.c, super.c: Massive changes to avoid using printf and com_err
routines. All diagnostic messages are now routed through the
fix_problem interface.
pass2.c (check_dir_block): Check for duplicate '.' and '..' entries.
problem.c, problem.h: Add new problem codes PR_2_DUP_DOT and
PR_2_DUP_DOT_DOT.
problem.c: Added new problem codes for some of the superblock
corruption checks, and for the pass header messages. ("Pass
1: xxxxx")
util.c (print_resource_track): Now takes a description argument.
super.c, unix.c, e2fsck.c: New files to separate out the
operating-specific operations out from e2fsck.c. e2fsck.c now
contains the global e2fsck context management routines, and
super.c contains the "pass 0" initial validation of the
superblock and global block group descriptors.
pass1.c, pass2.c, pass3.c, pass4.c, pass5.c, util.c: Eliminate
(nearly) all global variables and moved them to the e2fsck
context structure.
problem.c, problem.h: Added new problem codes PR_0_SB_CORRUPT,
PR_0_FS_SIZE_WRONG, PR_0_NO_FRAGMENTS, PR_0_BLOCKS_PER_GROUP,
PR_0_FIRST_DATA_BLOCK
expect.1, expect.2:
Updated tests to align with e2fsck problem.c changes.
1997-10-03 21:48:10 +04:00
|
|
|
if (ctx->options & E2F_OPT_TIME)
|
|
|
|
ctx->options |= E2F_OPT_TIME2;
|
|
|
|
else
|
|
|
|
ctx->options |= E2F_OPT_TIME;
|
1997-10-20 05:38:32 +04:00
|
|
|
#else
|
|
|
|
fprintf(stderr, "The -t option is not "
|
|
|
|
"supported on this version of e2fsck.\n");
|
|
|
|
#endif
|
Many files:
pass*.c, super.c: Massive changes to avoid using printf and com_err
routines. All diagnostic messages are now routed through the
fix_problem interface.
pass2.c (check_dir_block): Check for duplicate '.' and '..' entries.
problem.c, problem.h: Add new problem codes PR_2_DUP_DOT and
PR_2_DUP_DOT_DOT.
problem.c: Added new problem codes for some of the superblock
corruption checks, and for the pass header messages. ("Pass
1: xxxxx")
util.c (print_resource_track): Now takes a description argument.
super.c, unix.c, e2fsck.c: New files to separate out the
operating-specific operations out from e2fsck.c. e2fsck.c now
contains the global e2fsck context management routines, and
super.c contains the "pass 0" initial validation of the
superblock and global block group descriptors.
pass1.c, pass2.c, pass3.c, pass4.c, pass5.c, util.c: Eliminate
(nearly) all global variables and moved them to the e2fsck
context structure.
problem.c, problem.h: Added new problem codes PR_0_SB_CORRUPT,
PR_0_FS_SIZE_WRONG, PR_0_NO_FRAGMENTS, PR_0_BLOCKS_PER_GROUP,
PR_0_FIRST_DATA_BLOCK
expect.1, expect.2:
Updated tests to align with e2fsck problem.c changes.
1997-10-03 21:48:10 +04:00
|
|
|
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 = malloc(strlen(optarg)+1);
|
|
|
|
if (!bad_blocks_file)
|
|
|
|
fatal_error("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 ("-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 (ctx->device_name == 0)
|
|
|
|
ctx->device_name = ctx->filesystem_name;
|
|
|
|
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 ("BLKFLSBUF not supported");
|
|
|
|
#endif /* BLKFLSBUF */
|
|
|
|
}
|
|
|
|
if (swapfs) {
|
|
|
|
if (cflag || bad_blocks_file) {
|
|
|
|
fprintf(stderr, "Incompatible options not "
|
|
|
|
"allowed when byte-swapping.\n");
|
|
|
|
fatal_error(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;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
1997-10-20 05:38:32 +04:00
|
|
|
#ifdef RESOURCE_TRACK
|
Many files:
pass*.c, super.c: Massive changes to avoid using printf and com_err
routines. All diagnostic messages are now routed through the
fix_problem interface.
pass2.c (check_dir_block): Check for duplicate '.' and '..' entries.
problem.c, problem.h: Add new problem codes PR_2_DUP_DOT and
PR_2_DUP_DOT_DOT.
problem.c: Added new problem codes for some of the superblock
corruption checks, and for the pass header messages. ("Pass
1: xxxxx")
util.c (print_resource_track): Now takes a description argument.
super.c, unix.c, e2fsck.c: New files to separate out the
operating-specific operations out from e2fsck.c. e2fsck.c now
contains the global e2fsck context management routines, and
super.c contains the "pass 0" initial validation of the
superblock and global block group descriptors.
pass1.c, pass2.c, pass3.c, pass4.c, pass5.c, util.c: Eliminate
(nearly) all global variables and moved them to the e2fsck
context structure.
problem.c, problem.h: Added new problem codes PR_0_SB_CORRUPT,
PR_0_FS_SIZE_WRONG, PR_0_NO_FRAGMENTS, PR_0_BLOCKS_PER_GROUP,
PR_0_FIRST_DATA_BLOCK
expect.1, expect.2:
Updated tests to align with e2fsck problem.c changes.
1997-10-03 21:48:10 +04:00
|
|
|
init_resource_track(&ctx->global_rtrack);
|
1997-10-20 05:38:32 +04:00
|
|
|
#endif
|
Many files:
pass*.c, super.c: Massive changes to avoid using printf and com_err
routines. All diagnostic messages are now routed through the
fix_problem interface.
pass2.c (check_dir_block): Check for duplicate '.' and '..' entries.
problem.c, problem.h: Add new problem codes PR_2_DUP_DOT and
PR_2_DUP_DOT_DOT.
problem.c: Added new problem codes for some of the superblock
corruption checks, and for the pass header messages. ("Pass
1: xxxxx")
util.c (print_resource_track): Now takes a description argument.
super.c, unix.c, e2fsck.c: New files to separate out the
operating-specific operations out from e2fsck.c. e2fsck.c now
contains the global e2fsck context management routines, and
super.c contains the "pass 0" initial validation of the
superblock and global block group descriptors.
pass1.c, pass2.c, pass3.c, pass4.c, pass5.c, util.c: Eliminate
(nearly) all global variables and moved them to the e2fsck
context structure.
problem.c, problem.h: Added new problem codes PR_0_SB_CORRUPT,
PR_0_FS_SIZE_WRONG, PR_0_NO_FRAGMENTS, PR_0_BLOCKS_PER_GROUP,
PR_0_FIRST_DATA_BLOCK
expect.1, expect.2:
Updated tests to align with e2fsck problem.c changes.
1997-10-03 21:48:10 +04:00
|
|
|
|
|
|
|
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))
|
|
|
|
die ("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
|
|
|
|
sync_disks();
|
|
|
|
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 ("Get a newer version of e2fsck!\n");
|
|
|
|
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");
|
|
|
|
else
|
|
|
|
fix_problem(ctx, PR_0_SB_CORRUPT, &pctx);
|
|
|
|
fatal_error(0);
|
|
|
|
}
|
|
|
|
ctx->fs = fs;
|
|
|
|
fs->private = 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);
|
|
|
|
goto get_newer;
|
|
|
|
}
|
|
|
|
#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);
|
|
|
|
get_newer:
|
|
|
|
printf ("Get a newer version of e2fsck!\n");
|
|
|
|
fatal_error(0);
|
|
|
|
}
|
|
|
|
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 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);
|
|
|
|
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 (normalize_swapfs) {
|
|
|
|
if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ==
|
|
|
|
ext2fs_native_flag()) {
|
|
|
|
fprintf(stderr, "%s: Filesystem byte order "
|
|
|
|
"already normalized.\n", ctx->device_name);
|
|
|
|
fatal_error(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (swapfs)
|
|
|
|
swap_filesys(ctx);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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");
|
|
|
|
}
|
|
|
|
|
|
|
|
pass1(ctx);
|
|
|
|
if (restart_e2fsck) {
|
|
|
|
ext2fs_close(fs);
|
|
|
|
printf("Restarting e2fsck from the beginning...\n");
|
|
|
|
restart_e2fsck = 0;
|
|
|
|
retval = e2fsck_reset_context(ctx);
|
|
|
|
if (retval) {
|
|
|
|
com_err(ctx->program_name, retval,
|
|
|
|
"while resetting context");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
goto restart;
|
|
|
|
}
|
|
|
|
pass2(ctx);
|
|
|
|
pass3(ctx);
|
|
|
|
pass4(ctx);
|
|
|
|
pass5(ctx);
|
|
|
|
|
|
|
|
#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);
|
|
|
|
|
|
|
|
write_bitmaps(ctx);
|
|
|
|
ext2fs_close(fs);
|
|
|
|
sync_disks();
|
|
|
|
|
1997-10-20 05:38:32 +04:00
|
|
|
#ifdef RESOURCE_TRACK
|
Many files:
pass*.c, super.c: Massive changes to avoid using printf and com_err
routines. All diagnostic messages are now routed through the
fix_problem interface.
pass2.c (check_dir_block): Check for duplicate '.' and '..' entries.
problem.c, problem.h: Add new problem codes PR_2_DUP_DOT and
PR_2_DUP_DOT_DOT.
problem.c: Added new problem codes for some of the superblock
corruption checks, and for the pass header messages. ("Pass
1: xxxxx")
util.c (print_resource_track): Now takes a description argument.
super.c, unix.c, e2fsck.c: New files to separate out the
operating-specific operations out from e2fsck.c. e2fsck.c now
contains the global e2fsck context management routines, and
super.c contains the "pass 0" initial validation of the
superblock and global block group descriptors.
pass1.c, pass2.c, pass3.c, pass4.c, pass5.c, util.c: Eliminate
(nearly) all global variables and moved them to the e2fsck
context structure.
problem.c, problem.h: Added new problem codes PR_0_SB_CORRUPT,
PR_0_FS_SIZE_WRONG, PR_0_NO_FRAGMENTS, PR_0_BLOCKS_PER_GROUP,
PR_0_FIRST_DATA_BLOCK
expect.1, expect.2:
Updated tests to align with e2fsck problem.c changes.
1997-10-03 21:48:10 +04:00
|
|
|
if (ctx->options & E2F_OPT_TIME)
|
|
|
|
print_resource_track(NULL, &ctx->global_rtrack);
|
1997-10-20 05:38:32 +04:00
|
|
|
#endif
|
Many files:
pass*.c, super.c: Massive changes to avoid using printf and com_err
routines. All diagnostic messages are now routed through the
fix_problem interface.
pass2.c (check_dir_block): Check for duplicate '.' and '..' entries.
problem.c, problem.h: Add new problem codes PR_2_DUP_DOT and
PR_2_DUP_DOT_DOT.
problem.c: Added new problem codes for some of the superblock
corruption checks, and for the pass header messages. ("Pass
1: xxxxx")
util.c (print_resource_track): Now takes a description argument.
super.c, unix.c, e2fsck.c: New files to separate out the
operating-specific operations out from e2fsck.c. e2fsck.c now
contains the global e2fsck context management routines, and
super.c contains the "pass 0" initial validation of the
superblock and global block group descriptors.
pass1.c, pass2.c, pass3.c, pass4.c, pass5.c, util.c: Eliminate
(nearly) all global variables and moved them to the e2fsck
context structure.
problem.c, problem.h: Added new problem codes PR_0_SB_CORRUPT,
PR_0_FS_SIZE_WRONG, PR_0_NO_FRAGMENTS, PR_0_BLOCKS_PER_GROUP,
PR_0_FIRST_DATA_BLOCK
expect.1, expect.2:
Updated tests to align with e2fsck problem.c changes.
1997-10-03 21:48:10 +04:00
|
|
|
|
|
|
|
e2fsck_free_context(ctx);
|
|
|
|
|
|
|
|
return exit_value;
|
|
|
|
}
|