From: Theodore Ts'o Date: Mon, 6 May 2019 05:10:53 +0000 (-0400) Subject: e2fsck: add support for saving the problem code log X-Git-Tag: v1.45.1-rc1~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d2dd606fab56205fc6a57887ca8cd1ae0310776e;p=thirdparty%2Fe2fsprogs.git e2fsck: add support for saving the problem code log Add the ability to save a log of problems found by e2fsck in a log file that can be specified via /etc/e2fsck.conf. Signed-off-by: Theodore Ts'o --- diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c index 88088a257..2af610529 100644 --- a/e2fsck/e2fsck.c +++ b/e2fsck/e2fsck.c @@ -215,6 +215,12 @@ void e2fsck_free_context(e2fsck_t ctx) if (ctx->logf) fclose(ctx->logf); + if (ctx->problem_log_fn) + free(ctx->problem_log_fn); + + if (ctx->problem_logf) + fclose(ctx->problem_logf); + ext2fs_free_mem(&ctx); } diff --git a/e2fsck/e2fsck.conf.5.in b/e2fsck/e2fsck.conf.5.in index 708e21346..48ad0fde1 100644 --- a/e2fsck/e2fsck.conf.5.in +++ b/e2fsck/e2fsck.conf.5.in @@ -175,7 +175,9 @@ defaults to false. .I log_dir If the .I log_filename -relation contains a relative pathname, then the log file will be placed +or +.I problem_log_filename +relations contains a relative pathname, then the log file will be placed in the directory named by the .I log_dir relation. @@ -224,6 +226,16 @@ end up delaying the boot process for a long time (potentially hours). If this boolean relation is true, do not offer to optimize the extent tree by reducing the tree's width or depth. This setting defaults to false. .TP +.I problem_log_filename +This relation specifies the file name where a log of problem codes +found by e2fsck be written. The filename may contain various +percent-expressions (%D, %T, %N, +etc.) which will be expanded so that the file name for the log file can +include things like date, time, device name, and other run-time +parameters. See the +.B LOGGING +section for more details. +.TP .I readahead_mem_pct Use this percentage of memory to try to read in metadata blocks ahead of the main e2fsck thread. This should reduce run times, depending on the speed of diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index 1c7a67cba..2d359b384 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -231,6 +231,8 @@ struct e2fsck_struct { char *io_options; FILE *logf; char *log_fn; + FILE *problem_logf; + char *problem_log_fn; int flags; /* E2fsck internal flags */ int options; int blocksize; /* blocksize */ diff --git a/e2fsck/logfile.c b/e2fsck/logfile.c index e004f31a9..3eeefd192 100644 --- a/e2fsck/logfile.c +++ b/e2fsck/logfile.c @@ -285,8 +285,9 @@ static FILE *save_output(const char *s0, const char *s1, const char *s2) } #ifndef TEST_PROGRAM -void set_up_logging(e2fsck_t ctx) +static FILE *set_up_log_file(e2fsck_t ctx, const char *key, const char *fn) { + FILE *f = NULL; struct string s, s1, s2; char *s0 = 0, *log_dir = 0, *log_fn = 0; int log_dir_wait = 0; @@ -295,10 +296,10 @@ void set_up_logging(e2fsck_t ctx) profile_get_boolean(ctx->profile, "options", "log_dir_wait", 0, 0, &log_dir_wait); - if (ctx->log_fn) - log_fn = string_copy(ctx, ctx->log_fn, 0); + if (fn) + log_fn = string_copy(ctx, fn, 0); else - profile_get_string(ctx->profile, "options", "log_filename", + profile_get_string(ctx->profile, "options", key, 0, 0, &log_fn); profile_get_string(ctx->profile, "options", "log_dir", 0, 0, &log_dir); @@ -328,13 +329,13 @@ void set_up_logging(e2fsck_t ctx) } if (s0) - ctx->logf = fopen(s0, "w"); - if (!ctx->logf && s1.s) - ctx->logf = fopen(s1.s, "w"); - if (!ctx->logf && s2.s) - ctx->logf = fopen(s2.s, "w"); - if (!ctx->logf && log_dir_wait) - ctx->logf = save_output(s0, s1.s, s2.s); + f = fopen(s0, "w"); + if (!f && s1.s) + f = fopen(s1.s, "w"); + if (!f && s2.s) + f = fopen(s2.s, "w"); + if (!f && log_dir_wait) + f = save_output(s0, s1.s, s2.s); out: free(s.s); @@ -342,7 +343,14 @@ out: free(s2.s); free(log_fn); free(log_dir); - return; + return f; +} + +void set_up_logging(e2fsck_t ctx) +{ + ctx->logf = set_up_log_file(ctx, "log_filename", ctx->log_fn); + ctx->problem_logf = set_up_log_file(ctx, "problem_log_filename", + ctx->problem_log_fn); } #else void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size, diff --git a/e2fsck/problem.c b/e2fsck/problem.c index 0e6bacec2..01f086737 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -515,7 +515,7 @@ static struct e2fsck_problem problem_table[] = { /* Pass 1: Checking inodes, blocks, and sizes */ { PR_1_PASS_HEADER, N_("Pass 1: Checking @is, @bs, and sizes\n"), - PROMPT_NONE, 0, 0, 0, 0 }, + PROMPT_NONE, PR_HEADER, 0, 0, 0 }, /* Root inode is not a directory */ { PR_1_ROOT_NO_DIR, N_("@r is not a @d. "), @@ -1190,7 +1190,7 @@ static struct e2fsck_problem problem_table[] = { { PR_1B_PASS_HEADER, N_("\nRunning additional passes to resolve @bs claimed by more than one @i...\n" "Pass 1B: Rescanning for @m @bs\n"), - PROMPT_NONE, 0, 0, 0, 0 }, + PROMPT_NONE, PR_HEADER, 0, 0, 0 }, /* Duplicate/bad block(s) header */ { PR_1B_DUP_BLOCK_HEADER, @@ -1235,13 +1235,13 @@ static struct e2fsck_problem problem_table[] = { /* Pass 1C: Scan directories for inodes with multiply-claimed blocks. */ { PR_1C_PASS_HEADER, N_("Pass 1C: Scanning directories for @is with @m @bs\n"), - PROMPT_NONE, 0, 0, 0, 0 }, + PROMPT_NONE, PR_HEADER, 0, 0, 0 }, /* Pass 1D: Reconciling multiply-claimed blocks */ { PR_1D_PASS_HEADER, N_("Pass 1D: Reconciling @m @bs\n"), - PROMPT_NONE, 0, 0, 0, 0 }, + PROMPT_NONE, PR_HEADER, 0, 0, 0 }, /* File has duplicate blocks */ { PR_1D_DUP_FILE, @@ -1286,7 +1286,7 @@ static struct e2fsck_problem problem_table[] = { /* Pass 1E: Optimizing extent trees */ { PR_1E_PASS_HEADER, N_("Pass 1E: Optimizing @x trees\n"), - PROMPT_NONE, PR_PREEN_NOMSG, 0, 0, 0 }, + PROMPT_NONE, PR_HEADER | PR_PREEN_NOMSG, 0, 0, 0 }, /* Failed to optimize extent tree */ { PR_1E_OPTIMIZE_EXT_ERR, @@ -1328,7 +1328,7 @@ static struct e2fsck_problem problem_table[] = { /* Pass 2: Checking directory structure */ { PR_2_PASS_HEADER, N_("Pass 2: Checking @d structure\n"), - PROMPT_NONE, 0, 0, 0, 0 }, + PROMPT_NONE, PR_HEADER, 0, 0, 0 }, /* Bad inode number for '.' */ { PR_2_BAD_INODE_DOT, @@ -1694,7 +1694,7 @@ static struct e2fsck_problem problem_table[] = { /* Pass 3: Checking directory connectivity */ { PR_3_PASS_HEADER, N_("Pass 3: Checking @d connectivity\n"), - PROMPT_NONE, 0, 0, 0, 0 }, + PROMPT_NONE, PR_HEADER, 0, 0, 0 }, /* Root inode not allocated */ { PR_3_NO_ROOT_INODE, @@ -1836,7 +1836,7 @@ static struct e2fsck_problem problem_table[] = { /* Pass 3A: Optimizing directories */ { PR_3A_PASS_HEADER, N_("Pass 3A: Optimizing directories\n"), - PROMPT_NONE, PR_PREEN_NOMSG, 0, 0, 0 }, + PROMPT_NONE, PR_HEADER | PR_PREEN_NOMSG, 0, 0, 0 }, /* Error iterating over directories */ { PR_3A_OPTIMIZE_ITER, @@ -1868,7 +1868,7 @@ static struct e2fsck_problem problem_table[] = { /* Pass 4: Checking reference counts */ { PR_4_PASS_HEADER, N_("Pass 4: Checking reference counts\n"), - PROMPT_NONE, 0, 0, 0, 0 }, + PROMPT_NONE, PR_HEADER, 0, 0, 0 }, /* Unattached zero-length inode */ { PR_4_ZERO_LEN_INODE, @@ -1906,7 +1906,7 @@ static struct e2fsck_problem problem_table[] = { /* Pass 5: Checking group summary information */ { PR_5_PASS_HEADER, N_("Pass 5: Checking @g summary information\n"), - PROMPT_NONE, 0, 0, 0, 0 }, + PROMPT_NONE, PR_HEADER, 0, 0, 0 }, /* Padding at end of inode bitmap is not set. */ { PR_5_INODE_BMAP_PADDING, @@ -2191,6 +2191,45 @@ static void reconfigure_bool(e2fsck_t ctx, struct e2fsck_problem *ptr, ptr->flags &= ~mask; } +static void print_problem(FILE *f, problem_t code, int answer, int fixed, + struct e2fsck_problem *ptr, + struct problem_context *pctx) +{ + if (ptr->flags & PR_HEADER) { + fprintf(f, "
\n", code); + return; + } + fprintf(f, "errcode) + fprintf(f, " errcode=\"%lu\"", pctx->errcode); + if (fixed) + fputs(" fixed=\"1\"", f); + if (pctx->ino) + fprintf(f, " ino=\"%lu\"", pctx->ino); + if (pctx->ino2) + fprintf(f, " ino2=\"%lu\"", pctx->ino2); + if (pctx->dir) + fprintf(f, " dir=\"%lu\"", pctx->dir); + if (pctx->blk) + fprintf(f, " blk=\"%llu\"", pctx->blk); + if (pctx->blk2) + fprintf(f, " blk2=\"%llu\"", pctx->blk2); + if (pctx->blkcount != (e2_blkcnt_t) -1) + fprintf(f, " blkcount=\"%lld\"", pctx->blkcount); + if (pctx->group != (dgrp_t) -1) + fprintf(f, " group=\"%lu\"", pctx->group); + if (pctx->csum1) + fprintf(f, " csum1=\"%lu\"", pctx->csum1); + if (pctx->csum2) + fprintf(f, " csum2=\"%lu\"", pctx->csum2); + if (pctx->num) + fprintf(f, " num=\"%llu\"", pctx->num); + if (pctx->num2) + fprintf(f, " num2=\"%llu\"", pctx->num2); + if (pctx->str) + fprintf(f, " str=\"%s\"", pctx->str); + fputs("/>\n", f); +} int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx) { @@ -2201,6 +2240,7 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx) int def_yn, answer, ans; int print_answer = 0; int suppress = 0; + int fixed = 0; ptr = find_problem(code); if (!ptr) { @@ -2275,6 +2315,9 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx) (ldesc->flags & (PRL_YES | PRL_NO))) suppress++; if (ptr->count == ptr->max_count + 1) { + if (ctx->problem_logf) + fprintf(ctx->problem_logf, + "\n", code); printf("...problem 0x%06x suppressed\n", ptr->e2p_code); fflush(stdout); @@ -2345,8 +2388,14 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx) answer = fix_problem(ctx, ptr->second_code, pctx); if (answer && (ptr->prompt != PROMPT_NONE) && - !(ptr->flags & PR_NOT_A_FIX)) + !(ptr->flags & PR_NOT_A_FIX)) { + fixed = 1; ctx->flags |= E2F_FLAG_PROBLEMS_FIXED; + } + + if (ctx->problem_logf) + print_problem(ctx->problem_logf, code, answer, fixed, + ptr, pctx); return answer; } diff --git a/e2fsck/problemP.h b/e2fsck/problemP.h index 63bb8df6c..95c1a704e 100644 --- a/e2fsck/problemP.h +++ b/e2fsck/problemP.h @@ -45,3 +45,4 @@ struct latch_descr { from the config file */ #define PR_FORCE_NO 0x100000 /* Force the answer to be no */ #define PR_NOT_A_FIX 0x200000 /* Yes doesn't mean a problem was fixed */ +#define PR_HEADER 0x400000 /* Problem is a header marker */ diff --git a/e2fsck/unix.c b/e2fsck/unix.c index 37fca0f18..f8c4983d9 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -50,6 +50,7 @@ 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 "e2fsck.h" #include "problem.h" @@ -736,6 +737,12 @@ 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; @@ -1417,6 +1424,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) @@ -1425,6 +1433,17 @@ 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, "problem_logf, " arg=\"%s\"", argv[i]); + fputs(">\n", ctx->problem_logf); + } init_resource_track(&ctx->global_rtrack, NULL); if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) @@ -1682,6 +1701,24 @@ failure: if (isspace(*cp) || *cp == ':') *cp = '_'; + if (ctx->problem_logf) { + char buf[48]; + + fprintf(ctx->problem_logf, "filesystem_name); + if (!uuid_is_null(sb->s_uuid)) { + uuid_unparse(sb->s_uuid, buf); + fprintf(ctx->problem_logf, " uuid=\"%s\"", buf); + } + if (sb->s_volume_name[0]) { + memset(buf, 0, sizeof(buf)); + strncpy(buf, sb->s_volume_name, + sizeof(sb->s_volume_name)); + fprintf(ctx->problem_logf, " label=\"%s\"", buf); + } + fputs(">\n", ctx->problem_logf); + } + ehandler_init(fs->io); if (ext2fs_has_feature_mmp(fs->super) &&