}
#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;
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);
}
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);
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,
/* 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. "),
{ 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,
/* 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,
/* 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,
/* 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,
/* 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,
/* 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,
/* 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,
/* 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,
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, "<header code=\"0x%06x\">\n", code);
+ return;
+ }
+ fprintf(f, "<problem code=\"0x%06x\" answer=\"%d\"", code, answer);
+ if (pctx->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)
{
int def_yn, answer, ans;
int print_answer = 0;
int suppress = 0;
+ int fixed = 0;
ptr = find_problem(code);
if (!ptr) {
(ldesc->flags & (PRL_YES | PRL_NO)))
suppress++;
if (ptr->count == ptr->max_count + 1) {
+ if (ctx->problem_logf)
+ fprintf(ctx->problem_logf,
+ "<suppressed code=\"0x%06x\">\n", code);
printf("...problem 0x%06x suppressed\n",
ptr->e2p_code);
fflush(stdout);
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;
}
#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"
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;
set_up_logging(ctx);
if (ctx->logf) {
int i;
+
fputs("E2fsck run: ", ctx->logf);
for (i = 0; i < argc; i++) {
if (i)
}
fputc('\n', ctx->logf);
}
+ if (ctx->problem_logf) {
+ int i;
+
+ fputs("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
+ ctx->problem_logf);
+ fprintf(ctx->problem_logf, "<invocation prog=\"%s\"",
+ argv[0]);
+ for (i = 1; i < argc; i++)
+ fprintf(ctx->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)
if (isspace(*cp) || *cp == ':')
*cp = '_';
+ if (ctx->problem_logf) {
+ char buf[48];
+
+ fprintf(ctx->problem_logf, "<filesystem dev=\"%s\"",
+ ctx->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) &&