X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=e2fsck%2Funix.c;h=853eb29644ad6c9622d4c95805f344770e82b88b;hb=b84eee32d54b20679b27cdff231cd72619e4cc44;hp=55e21ea0aeacac092c43ee9625573b7aa054a3fe;hpb=35b459ffd7b8b60671debe7233d5c558db1afafd;p=tools%2Fe2fsprogs.git diff --git a/e2fsck/unix.c b/e2fsck/unix.c index 55e21ea..853eb29 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -50,7 +50,9 @@ extern int optind; #include "e2p/e2p.h" #include "et/com_err.h" #include "e2p/e2p.h" +#include "uuid/uuid.h" #include "support/plausible.h" +#include "support/devname.h" #include "e2fsck.h" #include "problem.h" #include "jfs_user.h" @@ -77,7 +79,7 @@ static void usage(e2fsck_t ctx) _("Usage: %s [-panyrcdfktvDFV] [-b superblock] [-B blocksize]\n" "\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n" "\t\t[-E extended-options] [-z undo_file] device\n"), - ctx->program_name); + ctx->program_name ? ctx->program_name : "e2fsck"); fprintf(stderr, "%s", _("\nEmergency help:\n" " -p Automatic repair (no questions)\n" @@ -137,7 +139,8 @@ static void show_stats(e2fsck_t ctx) "%llu/%llu blocks\n"), ctx->device_name, inodes_used, inodes, frag_percent_total / 10, frag_percent_total % 10, - blocks_used, blocks); + (unsigned long long) blocks_used, + (unsigned long long) blocks); return; } profile_get_boolean(ctx->profile, "options", "report_features", 0, 0, @@ -193,7 +196,8 @@ static void show_stats(e2fsck_t ctx) log_out(ctx, P_("%12llu block used (%2.2f%%, out of %llu)\n", "%12llu blocks used (%2.2f%%, out of %llu)\n", blocks_used), - blocks_used, 100.0 * blocks_used / blocks, blocks); + (unsigned long long) blocks_used, 100.0 * blocks_used / blocks, + (unsigned long long) blocks); log_out(ctx, P_("%12u bad block\n", "%12u bad blocks\n", ctx->fs_badblocks_count), ctx->fs_badblocks_count); log_out(ctx, P_("%12u large file\n", "%12u large files\n", @@ -287,7 +291,7 @@ static int is_on_batt(void) { FILE *f; DIR *d; - char tmp[80], tmp2[80], fname[80]; + char tmp[80], tmp2[80], fname[NAME_MAX+30]; unsigned int acflag; struct dirent* de; @@ -301,7 +305,7 @@ static int is_on_batt(void) } f = fopen("/proc/apm", "r"); if (f) { - if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4) + if (fscanf(f, "%79s %79s %79s %x", tmp, tmp, tmp, &acflag) != 4) acflag = 1; fclose(f); return (acflag != 1); @@ -311,12 +315,13 @@ static int is_on_batt(void) while ((de=readdir(d)) != NULL) { if (!strncmp(".", de->d_name, 1)) continue; - snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state", + snprintf(fname, sizeof(fname), + "/proc/acpi/ac_adapter/%s/state", de->d_name); f = fopen(fname, "r"); if (!f) continue; - if (fscanf(f, "%s %s", tmp2, tmp) != 2) + if (fscanf(f, "%79s %79s", tmp2, tmp) != 2) tmp[0] = 0; fclose(f); if (strncmp(tmp, "off-line", 8) == 0) { @@ -442,9 +447,9 @@ static void check_if_skip(e2fsck_t ctx) ctx->device_name, fs->super->s_inodes_count - fs->super->s_free_inodes_count, fs->super->s_inodes_count, - ext2fs_blocks_count(fs->super) - + (unsigned long long) ext2fs_blocks_count(fs->super) - ext2fs_free_blocks_count(fs->super), - ext2fs_blocks_count(fs->super)); + (unsigned long long) ext2fs_blocks_count(fs->super)); next_check = 100000; if (fs->super->s_max_mnt_count > 0) { next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count; @@ -616,9 +621,10 @@ static void reserve_stdio_fds(void) fprintf(stderr, _("ERROR: Couldn't open " "/dev/null (%s)\n"), strerror(errno)); - break; + return; } } + (void) close(fd); } #ifdef HAVE_SIGNAL_H @@ -734,12 +740,30 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts) else ctx->log_fn = string_copy(ctx, arg, 0); continue; + } else if (strcmp(token, "problem_log") == 0) { + if (!arg) + extended_usage++; + else + ctx->problem_log_fn = string_copy(ctx, arg, 0); + continue; } else if (strcmp(token, "bmap2extent") == 0) { ctx->options |= E2F_OPT_CONVERT_BMAP; continue; } else if (strcmp(token, "fixes_only") == 0) { ctx->options |= E2F_OPT_FIXES_ONLY; continue; + } else if (strcmp(token, "unshare_blocks") == 0) { + ctx->options |= E2F_OPT_UNSHARE_BLOCKS; + ctx->options |= E2F_OPT_FORCE; + continue; + } else if (strcmp(token, "check_encoding") == 0) { + ctx->options |= E2F_OPT_CHECK_ENCODING; + continue; +#ifdef CONFIG_DEVELOPER_FEATURES + } else if (strcmp(token, "clear_all_uninit_bits") == 0) { + ctx->options |= E2F_OPT_CLEAR_UNINIT; + continue; +#endif } else { fprintf(stderr, _("Unknown extended option: %s\n"), token); @@ -764,7 +788,9 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts) fputs("\tno_inode_count_fullmap\n", stderr); fputs(_("\treadahead_kb=\n"), stderr); fputs("\tbmap2extent\n", stderr); + fputs("\tunshare_blocks\n", stderr); fputs("\tfixes_only\n", stderr); + fputs("\tcheck_encoding\n", stderr); fputc('\n', stderr); exit(1); } @@ -798,7 +824,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) #ifdef CONFIG_JBD_DEBUG char *jbd_debug; #endif - unsigned long long phys_mem_kb; + unsigned long long phys_mem_kb, blk; retval = e2fsck_allocate_context(&ctx); if (retval) @@ -824,7 +850,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) if (argc && *argv) ctx->program_name = *argv; else - ctx->program_name = "e2fsck"; + usage(NULL); phys_mem_kb = get_memory_size() / 1024; ctx->readahead_kb = ~0ULL; @@ -899,7 +925,8 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) /* What we do by default, anyway! */ break; case 'b': - res = sscanf(optarg, "%llu", &ctx->use_superblock); + res = sscanf(optarg, "%llu", &blk); + ctx->use_superblock = blk; if (res != 1) goto sscanf_err; ctx->flags |= E2F_FLAG_SB_SPECIFIED; @@ -913,8 +940,8 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) goto sscanf_err; break; case 'j': - ctx->journal_name = blkid_get_devname(ctx->blkid, - optarg, NULL); + ctx->journal_name = get_devname(ctx->blkid, + optarg, NULL); if (!ctx->journal_name) { com_err(ctx->program_name, 0, _("Unable to resolve '%s'"), @@ -929,6 +956,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) break; case 'L': replace_bad_blocks++; + /* fall through */ case 'l': if (bad_blocks_file) free(bad_blocks_file); @@ -992,7 +1020,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) ctx->io_options = strchr(argv[optind], '?'); if (ctx->io_options) *ctx->io_options++ = 0; - ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0); + ctx->filesystem_name = get_devname(ctx->blkid, argv[optind], 0); if (!ctx->filesystem_name) { com_err(ctx->program_name, 0, _("Unable to resolve '%s'"), argv[optind]); @@ -1144,25 +1172,32 @@ static errcode_t try_open_fs(e2fsck_t ctx, int flags, io_manager io_ptr, errcode_t retval; *ret_fs = NULL; - if (ctx->superblock && ctx->blocksize) { - retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, - flags, ctx->superblock, ctx->blocksize, - io_ptr, ret_fs); - } else if (ctx->superblock) { - int blocksize; - for (blocksize = EXT2_MIN_BLOCK_SIZE; - blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) { - if (*ret_fs) { - ext2fs_free(*ret_fs); - *ret_fs = NULL; + + if (ctx->superblock) { + unsigned long blocksize = ctx->blocksize; + + if (!blocksize) { + for (blocksize = EXT2_MIN_BLOCK_SIZE; + blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) { + + retval = ext2fs_open2(ctx->filesystem_name, + ctx->io_options, flags, + ctx->superblock, blocksize, + unix_io_manager, ret_fs); + if (*ret_fs) { + ext2fs_free(*ret_fs); + *ret_fs = NULL; + } + if (!retval) + break; } - retval = ext2fs_open2(ctx->filesystem_name, - ctx->io_options, flags, - ctx->superblock, blocksize, - io_ptr, ret_fs); - if (!retval) - break; + if (retval) + return retval; } + + retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, + flags, ctx->superblock, blocksize, + io_ptr, ret_fs); } else retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, flags, 0, 0, io_ptr, ret_fs); @@ -1250,7 +1285,8 @@ check_error: dump_mmp_msg(fs->mmp_buf, _("If you are sure the filesystem is not " "in use on any node, run:\n" - "'tune2fs -f -E clear_mmp {device}'\n")); + "'tune2fs -f -E clear_mmp %s'\n"), + ctx->device_name); } else if (retval == EXT2_ET_MMP_MAGIC_INVALID) { if (fix_problem(ctx, PR_0_MMP_INVALID_MAGIC, &pctx)) { ext2fs_mmp_clear(fs); @@ -1373,6 +1409,7 @@ int main (int argc, char *argv[]) __u32 features[3]; char *cp; enum quota_type qtype; + struct ext2fs_journal_params jparams; clear_problem_context(&pctx); sigcatcher_setup(); @@ -1408,6 +1445,7 @@ int main (int argc, char *argv[]) set_up_logging(ctx); if (ctx->logf) { int i; + fputs("E2fsck run: ", ctx->logf); for (i = 0; i < argc; i++) { if (i) @@ -1416,6 +1454,19 @@ int main (int argc, char *argv[]) } fputc('\n', ctx->logf); } + if (ctx->problem_logf) { + int i; + + fputs("\n", + ctx->problem_logf); + fprintf(ctx->problem_logf, "\n", + (unsigned long) ctx->now); + fprintf(ctx->problem_logf, "problem_logf, " arg%d=\"%s\"", i, argv[i]); + fputs("/>\n", ctx->problem_logf); + } init_resource_track(&ctx->global_rtrack, NULL); if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) @@ -1439,7 +1490,7 @@ int main (int argc, char *argv[]) } ctx->superblock = ctx->use_superblock; - flags = EXT2_FLAG_SKIP_MMP; + flags = EXT2_FLAG_SKIP_MMP | EXT2_FLAG_THREADS; restart: #ifdef CONFIG_TESTIO_DEBUG if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { @@ -1576,7 +1627,9 @@ failure: * so that we are able to recover from more errors * (e.g. some tool messing up some value in the sb). */ - if (!(flags & EXT2_FLAG_IGNORE_SB_ERRORS)) { + if (((retval == EXT2_ET_CORRUPT_SUPERBLOCK) || + (retval == EXT2_ET_BAD_DESC_SIZE)) && + !(flags & EXT2_FLAG_IGNORE_SB_ERRORS)) { if (fs) ext2fs_close_free(&fs); log_out(ctx, _("%s: Trying to load superblock " @@ -1661,17 +1714,33 @@ failure: * Set the device name, which is used whenever we print error * or informational messages to the user. */ - if (ctx->device_name == 0 && - (sb->s_volume_name[0] != 0)) { - ctx->device_name = string_copy(ctx, sb->s_volume_name, + if (ctx->device_name == 0 && sb->s_volume_name[0]) + ctx->device_name = string_copy(ctx, (char *) sb->s_volume_name, sizeof(sb->s_volume_name)); - } + if (ctx->device_name == 0) ctx->device_name = string_copy(ctx, ctx->filesystem_name, 0); for (cp = ctx->device_name; *cp; cp++) if (isspace(*cp) || *cp == ':') *cp = '_'; + if (ctx->problem_logf) { + + fprintf(ctx->problem_logf, "filesystem_name); + if (!uuid_is_null(sb->s_uuid)) { + char buf[48]; + + uuid_unparse(sb->s_uuid, buf); + fprintf(ctx->problem_logf, " uuid=\"%s\"", buf); + } + if (sb->s_volume_name[0]) + fprintf(ctx->problem_logf, " label=\"%.*s\"", + EXT2_LEN_STR(sb->s_volume_name)); + + fputs("/>\n", ctx->problem_logf); + } + ehandler_init(fs->io); if (ext2fs_has_feature_mmp(fs->super) && @@ -1774,6 +1843,12 @@ print_unsupp_features: goto get_newer; } + if (ext2fs_has_feature_casefold(sb) && !fs->encoding) { + log_err(ctx, _("%s has unsupported encoding: %0x\n"), + ctx->filesystem_name, sb->s_encoding); + goto get_newer; + } + /* * If the user specified a specific superblock, presumably the * master superblock has been trashed. So we mark the @@ -1829,9 +1904,15 @@ print_unsupp_features: /* * Save the journal size in megabytes. * Try and use the journal size from the backup else let e2fsck - * find the default journal size. + * find the default journal size. If fast commit feature is enabled, + * it is not clear how many of the journal blocks were fast commit + * blocks. So, ignore the size of journal found in backup. + * + * TODO: Add a new backup type that captures fast commit info as + * well. */ - if (sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) + if (sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS && + !ext2fs_has_feature_fast_commit(sb)) journal_size = (sb->s_jnl_blocks[15] << (32 - 20)) | (sb->s_jnl_blocks[16] >> 20); else @@ -1853,20 +1934,16 @@ print_unsupp_features: if (!ctx->invalid_bitmaps && (ctx->flags & E2F_FLAG_JOURNAL_INODE)) { if (fix_problem(ctx, PR_6_RECREATE_JOURNAL, &pctx)) { - if (journal_size < 1024) - journal_size = ext2fs_default_journal_size(ext2fs_blocks_count(fs->super)); - if (journal_size < 0) { - ext2fs_clear_feature_journal(fs->super); - fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; - log_out(ctx, "%s: Couldn't determine " - "journal size\n", ctx->program_name); - goto no_journal; + if (journal_size < 1024) { + ext2fs_get_journal_params(&jparams, fs); + } else { + jparams.num_journal_blocks = journal_size; + jparams.num_fc_blocks = 0; } log_out(ctx, _("Creating journal (%d blocks): "), - journal_size); + jparams.num_journal_blocks); fflush(stdout); - retval = ext2fs_add_journal_inode(fs, - journal_size, 0); + retval = ext2fs_add_journal_inode3(fs, &jparams, ~0ULL, 0); if (retval) { log_out(ctx, "%s: while trying to create " "journal\n", error_message(retval)); @@ -1944,6 +2021,14 @@ no_journal: ext2fs_mark_super_dirty(fs); } + if (ext2fs_has_feature_shared_blocks(ctx->fs->super) && + (ctx->options & E2F_OPT_UNSHARE_BLOCKS) && + (ctx->options & E2F_OPT_NO)) + /* Don't try to write or flush I/O, we just wanted to know whether or + * not there were enough free blocks to undo deduplication. + */ + goto skip_write; + if (!(ctx->options & E2F_OPT_READONLY)) { e2fsck_write_bitmaps(ctx); if (fs->flags & EXT2_FLAG_DIRTY) { @@ -1980,6 +2065,8 @@ no_journal: exit_value |= FSCK_REBOOT; } } + +skip_write: if (!ext2fs_test_valid(fs) || ((exit_value & FSCK_CANCELED) && (sb->s_state & EXT2_ERROR_FS))) {