Whamcloud - gitweb
e2fsck: add logging capability
authorTheodore Ts'o <tytso@mit.edu>
Sun, 18 Mar 2012 03:21:00 +0000 (23:21 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Sun, 18 Mar 2012 19:40:47 +0000 (15:40 -0400)
Add the ability to log messages about a file system to a specified
directory, using a file name templace that can be specified in
/etc/e2fsck.conf.  This allows us to suppress the output of overly
verbose e2fsck outputs while still allowing the full logging output to
go to an appropriate file.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
e2fsck/Makefile.in
e2fsck/e2fsck.c
e2fsck/e2fsck.conf.5.in
e2fsck/e2fsck.h
e2fsck/logfile.c [new file with mode: 0644]
e2fsck/message.c
e2fsck/problem.c
e2fsck/problem.h
e2fsck/unix.c
e2fsck/util.c

index b5336a4..d558985 100644 (file)
@@ -68,7 +68,7 @@ OBJS= crc32.o dict.o unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o \
        pass3.o pass4.o pass5.o journal.o badblocks.o util.o dirinfo.o \
        dx_dirinfo.o ehandler.o problem.o message.o quota.o recovery.o \
        region.o revoke.o ea_refcount.o rehash.o profile.o prof_err.o \
-       sigcatcher.o $(MTRACE_OBJ)
+       logfile.o sigcatcher.o $(MTRACE_OBJ)
 
 PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \
        profiled/super.o profiled/pass1.o profiled/pass1b.o \
@@ -78,7 +78,8 @@ PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \
        profiled/message.o profiled/problem.o profiled/quota.o \
        profiled/recovery.o profiled/region.o profiled/revoke.o \
        profiled/ea_refcount.o profiled/rehash.o profiled/profile.o \
-       profiled/crc32.o profiled/prof_err.o profiled/sigcatcher.o
+       profiled/crc32.o profiled/prof_err.o profiled/logfile.o \
+       profiled/sigcatcher.o
 
 SRCS= $(srcdir)/e2fsck.c \
        $(srcdir)/crc32.c \
@@ -107,6 +108,7 @@ SRCS= $(srcdir)/e2fsck.c \
        $(srcdir)/region.c \
        $(srcdir)/profile.c \
        $(srcdir)/sigcatcher.c \
+       $(srcdir)/logfile.c \
        prof_err.c \
        $(srcdir)/quota.c \
        $(MTRACE_SRC)
@@ -160,6 +162,11 @@ tst_refcount: ea_refcount.c $(DEPLIBCOM_ERR)
        $(Q) $(CC) -o tst_refcount $(srcdir)/ea_refcount.c \
                $(ALL_CFLAGS) -DTEST_PROGRAM $(LIBCOM_ERR) $(LIBEXT2FS) 
 
+tst_logfile: $(srcdir)/logfile.c
+       $(E) "  LD $@"
+       $(Q) $(CC) -o tst_logfile $(srcdir)/logfile.c $(ALL_CFLAGS) \
+               -DTEST_PROGRAM
+
 tst_region: region.c $(DEPLIBCOM_ERR)
        $(E) "  LD $@"
        $(Q) $(CC) -o tst_region $(srcdir)/region.c \
@@ -279,7 +286,8 @@ distclean: clean
 # Makefile dependencies follow.  This must be the last section in
 # the Makefile.in file
 #
-e2fsck.o: $(srcdir)/e2fsck.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+e2fsck.o: $(srcdir)/e2fsck.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -288,7 +296,8 @@ e2fsck.o: $(srcdir)/e2fsck.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h
-crc32.o: $(srcdir)/crc32.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+crc32.o: $(srcdir)/crc32.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -297,10 +306,11 @@ crc32.o: $(srcdir)/crc32.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/crc32defs.h crc32table.h
-gen_crc32table.o: $(srcdir)/gen_crc32table.c $(top_builddir)/lib/config.h \
- $(srcdir)/crc32defs.h
-dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h $(srcdir)/dict.h
-super.o: $(srcdir)/super.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+gen_crc32table.o: $(srcdir)/gen_crc32table.c $(srcdir)/crc32defs.h
+dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/dict.h
+super.o: $(srcdir)/super.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -309,7 +319,8 @@ super.o: $(srcdir)/super.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h
-pass1.o: $(srcdir)/pass1.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+pass1.o: $(srcdir)/pass1.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -319,15 +330,17 @@ pass1.o: $(srcdir)/pass1.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h
 pass1b.o: $(srcdir)/pass1b.c $(top_builddir)/lib/config.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.h \
- $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
- $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h $(srcdir)/dict.h
-pass2.o: $(srcdir)/pass2.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+pass2.o: $(srcdir)/pass2.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -336,7 +349,8 @@ pass2.o: $(srcdir)/pass2.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h $(srcdir)/dict.h
-pass3.o: $(srcdir)/pass3.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+pass3.o: $(srcdir)/pass3.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -345,7 +359,8 @@ pass3.o: $(srcdir)/pass3.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h
-pass4.o: $(srcdir)/pass4.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+pass4.o: $(srcdir)/pass4.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -354,7 +369,8 @@ pass4.o: $(srcdir)/pass4.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h
-pass5.o: $(srcdir)/pass5.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+pass5.o: $(srcdir)/pass5.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -364,44 +380,49 @@ pass5.o: $(srcdir)/pass5.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h
 journal.o: $(srcdir)/journal.c $(top_builddir)/lib/config.h \
- $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
  $(top_srcdir)/lib/ext2fs/kernel-list.h $(srcdir)/problem.h
 recovery.o: $(srcdir)/recovery.c $(top_builddir)/lib/config.h \
- $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
  $(top_srcdir)/lib/ext2fs/kernel-list.h
 revoke.o: $(srcdir)/revoke.c $(top_builddir)/lib/config.h \
- $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
  $(top_srcdir)/lib/ext2fs/kernel-list.h
 badblocks.o: $(srcdir)/badblocks.c $(top_builddir)/lib/config.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.h \
- $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
- $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h
-util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -410,67 +431,74 @@ util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h
 unix.o: $(srcdir)/unix.c $(top_builddir)/lib/config.h \
- $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/et/com_err.h \
- $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h $(top_srcdir)/version.h
 dirinfo.o: $(srcdir)/dirinfo.c $(top_builddir)/lib/config.h \
- $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(top_srcdir)/lib/ext2fs/tdb.h
 dx_dirinfo.o: $(srcdir)/dx_dirinfo.c $(top_builddir)/lib/config.h \
- $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h
 ehandler.o: $(srcdir)/ehandler.c $(top_builddir)/lib/config.h \
- $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h
 problem.o: $(srcdir)/problem.c $(top_builddir)/lib/config.h \
- $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h $(srcdir)/problemP.h
 message.o: $(srcdir)/message.c $(top_builddir)/lib/config.h \
- $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h
 ea_refcount.o: $(srcdir)/ea_refcount.c $(top_builddir)/lib/config.h \
- $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h
-rehash.o: $(srcdir)/rehash.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+rehash.o: $(srcdir)/rehash.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -479,7 +507,8 @@ rehash.o: $(srcdir)/rehash.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h
-region.o: $(srcdir)/region.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+region.o: $(srcdir)/region.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -488,17 +517,29 @@ region.o: $(srcdir)/region.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h
 profile.o: $(srcdir)/profile.c $(top_builddir)/lib/config.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/profile.h prof_err.h
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/profile.h prof_err.h
 sigcatcher.o: $(srcdir)/sigcatcher.c $(top_builddir)/lib/config.h \
- $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
+ $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h
+logfile.o: $(srcdir)/logfile.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h
 prof_err.o: prof_err.c
-quota.o: $(srcdir)/quota.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
+quota.o: $(srcdir)/quota.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
@@ -506,4 +547,5 @@ quota.o: $(srcdir)/quota.c $(top_builddir)/lib/config.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
  $(top_srcdir)/lib/quota/quota.h $(top_srcdir)/lib/../e2fsck/dict.h \
- $(srcdir)/problem.h
+ $(srcdir)/problem.h $(top_srcdir)/lib/quota/quotaio.h \
+ $(top_srcdir)/lib/quota/dqblk_v2.h $(top_srcdir)/lib/quota/quotaio_tree.h
index c6e137b..994f80e 100644 (file)
@@ -187,6 +187,9 @@ void e2fsck_free_context(e2fsck_t ctx)
        if (ctx->device_name)
                ext2fs_free_mem(&ctx->device_name);
 
+       if (ctx->log_fn)
+               free(ctx->log_fn);
+
        ext2fs_free_mem(&ctx);
 }
 
index a89d7b4..0d4651b 100644 (file)
@@ -136,6 +136,47 @@ filesystem checks (either based on time or number of mounts) should
 be doubled if the system is running on battery.  This setting defaults to 
 true.
 .TP
+.I log_dir
+If the
+.I log_filename
+relation contains a relative pathname, then the log file will be placed
+in the directory named by the
+.I log_dir
+relation.
+.TP
+.I log_dir_fallback
+This relation contains an alternate directory that will be used if the
+directory specified by
+.I log_dir
+is not available or is not writeable.
+.TP
+.I log_dir_wait
+If this boolean relation is true, them if the directories specified by
+.I log_dir
+or
+.I log_dir_fallback
+are not available or are not yet writeable, e2fsck will save the output
+in a memory buffer, and a child process will periodically test to see if
+the log directory has become available after the boot sequence has
+mounted the requiste filesytem for reading/writing.  This implements the
+functionality provided by
+.BR logsave (8)
+for e2fsck log files.
+.TP
+.I log_filename
+This relation specifies the file name where a copy of e2fsck's output
+will be written.   If certain problem reports are suppressed using the
+.I max_count_problems
+relation, (or on a per-problem basis using the
+.I max_count
+relation), the full set of problem reports will be written to the log
+file.  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 max_count_problems
 This relation specifies the maximum number of problem reports of a
 particular type will be printed to stdout before further problem reports
@@ -241,6 +282,76 @@ defaults to true.
 This relation controls whether or not the scratch file directory is used
 instead of an in-memory data structure when tracking inode counts.  It
 defaults to true.
+.SH LOGGING
+E2fsck has the facility to save the information from an e2fsck run in a
+directory so that a system administrator can review its output at their
+leisure.  This allows information captured during the automatic e2fsck
+preen run, as well as a manually started e2fsck run, to be saved for
+posterity.  This facility is controlled by the
+.IR log_filename ,
+.IR log_dir ,
+.IR log_dir_fallback ,
+and
+.I log_dir_wait
+relations in the
+.I [options]
+stanza.
+.PP
+The filename in
+.I log_filename
+may contain the following percent-expressions that will be expanded as
+follows.
+.TP
+.B %d
+The current day of the month
+.TP
+.B %D
+The current date; this is a equivalent of
+.B %Y%m%d
+.TP
+.B %h
+The hostname of the system.
+.TP
+.B %H
+The current hour in 24-hour format (00..23)
+.TP
+.B %m
+The current month as a two-digit number (01..12)
+.TP
+.B %M
+The current minute (00..59)
+.TP
+.B %N
+The name of the block device containing the file system, with any
+directory pathname stripped off.
+.TP
+.B %p
+The pid of the e2fsck process
+.TP
+.B %s
+The current time expressed as the number of seconds since 1970-01-01
+00:00:00 UTC
+.TP
+.B %S
+The current second (00..59)
+.TP
+.B %T
+The current time; this is equivalent of
+.B %H%M%S
+.TP
+.B %u
+The name of the user running e2fsck.
+.TP
+.B %U
+This percent expression does not expand to anything, but it signals that
+any following date or time expressions should be expressed in UTC time
+instead of the local timzeone.
+.TP
+.B %y
+The last two digits of the current year (00..99)
+.TP
+.B %Y
+The current year (i.e., 2012).
 .SH EXAMPLES
 The following recipe will prevent e2fsck from aborting during the boot
 process when a filesystem contains orphaned files.  (Of course, this is
@@ -259,6 +370,29 @@ things out may be dangerous.)
                        description = "@u @i %i.  "
 .br
                }
+.P
+The following recipe will cause an e2fsck logfile to be written to the
+directory /var/log/e2fsck, with a filename that contains the device
+name, the hostname of the system, the date, and time: e.g.,
+"e2fsck-sda3.server.INFO.20120314-112142".  If the directory containing
+/var/log is located on the root file system
+which is initially mounted read-only, then the output will be saved in
+memory and written out once the root file system has been remounted
+read/write.   To avoid too much detail from being written to the serial
+console (which could potentially slow down the boot sequence), only print
+no more than 16 instances of each type of file system corruption.
+.P
+.br
+       [options]
+.br
+               max_count_problems = 16
+.br
+               log_dir = /var/log/e2fsck
+.br
+               log_filename = e2fsck-%N.%h.INFO.%D-%T
+.br
+               log_dir_wait = true
+.P
 .SH FILES
 .TP
 .I /etc/e2fsck.conf
index ed8b0c7..971390e 100644 (file)
 #define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
 #endif
 
+#ifdef __GNUC__
+#define E2FSCK_ATTR(x) __attribute__(x)
+#else
+#define E2FSCK_ATTR(x)
+#endif
+
 #include "quota/mkquota.h"
 
 /*
@@ -214,6 +220,8 @@ struct e2fsck_struct {
        char *filesystem_name;
        char *device_name;
        char *io_options;
+       FILE    *logf;
+       char    *log_fn;
        int     flags;          /* E2fsck internal flags */
        int     options;
        int     blocksize;      /* blocksize */
@@ -449,6 +457,9 @@ extern int e2fsck_run_ext3_journal(e2fsck_t ctx);
 extern void e2fsck_move_ext3_journal(e2fsck_t ctx);
 extern int e2fsck_fix_ext3_journal_hint(e2fsck_t ctx);
 
+/* logfile.c */
+extern void set_up_logging(e2fsck_t ctx);
+
 /* quota.c */
 extern void e2fsck_hide_quota(e2fsck_t ctx);
 
@@ -498,8 +509,12 @@ void check_resize_inode(e2fsck_t ctx);
 extern void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
                                    const char *description);
 extern int ask(e2fsck_t ctx, const char * string, int def);
-extern int ask_yn(const char * string, int def);
+extern int ask_yn(e2fsck_t ctx, const char * string, int def);
 extern void fatal_error(e2fsck_t ctx, const char * fmt_string);
+extern void log_out(e2fsck_t ctx, const char *fmt, ...)
+       E2FSCK_ATTR((format(printf, 2, 3)));
+extern void log_err(e2fsck_t ctx, const char *fmt, ...)
+       E2FSCK_ATTR((format(printf, 2, 3)));
 extern void e2fsck_read_bitmaps(e2fsck_t ctx);
 extern void e2fsck_write_bitmaps(e2fsck_t ctx);
 extern void preenhalt(e2fsck_t ctx);
diff --git a/e2fsck/logfile.c b/e2fsck/logfile.c
new file mode 100644 (file)
index 0000000..76ae52d
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * logfile.c --- set up e2fsck log files
+ *
+ * Copyright 1996, 1997 by Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "config.h"
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "e2fsck.h"
+#include <pwd.h>
+
+struct string {
+       char    *s;
+       int     len;
+       int     end;
+};
+
+static void alloc_string(struct string *s, int len)
+{
+       s->s = malloc(len);
+/* e2fsck_allocate_memory(ctx, len, "logfile name"); */
+       s->len = len;
+       s->end = 0;
+}
+
+static void append_string(struct string *s, const char *a, int len)
+{
+       if (!len)
+               len = strlen(a);
+
+       if (s->end + len >= s->len) {
+               char *n = realloc(s, s->len * 2);
+
+               if (n) {
+                       s->s = n;
+                       s->len = s->len * 2;
+               } else {
+                       len = s->len - s->end - 1;
+                       if (len <= 0)
+                               return;
+               }
+       }
+       memcpy(s->s + s->end, a, len);
+       s->end += len;
+       s->s[s->end] = 0;
+}
+
+#define FLAG_UTC       0x0001
+
+static void expand_percent_expression(e2fsck_t ctx, char ch,
+                                     struct string *s, int *flags)
+{
+       struct tm       *tm = NULL, tm_struct;
+       struct passwd   *pw = NULL, pw_struct;
+       char            *cp;
+       char            buf[256];
+
+       if ((ch == 'D') || (ch == 'd') || (ch == 'm') || (ch == 'y') ||
+           (ch == 'Y') ||
+           (ch == 'T') || (ch == 'H') || (ch == 'M') || (ch == 'S')) {
+               tzset();
+               tm = (*flags & FLAG_UTC) ? gmtime_r(&ctx->now, &tm_struct) :
+                       localtime_r(&ctx->now, &tm_struct);
+       }
+
+       switch (ch) {
+       case '%':
+               append_string(s, "%", 1);
+               return;
+       case 'd':
+               sprintf(buf, "%02d", tm->tm_mday);
+               break;
+       case 'D':
+               sprintf(buf, "%d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1,
+                       tm->tm_mday);
+               break;
+       case 'h':
+#ifdef TEST_PROGRAM
+               strcpy(buf, "server");
+#else
+               buf[0] = 0;
+               gethostname(buf, sizeof(buf));
+               buf[sizeof(buf)-1] = 0;
+#endif
+               break;
+       case 'H':
+               sprintf(buf, "%02d", tm->tm_hour);
+               break;
+       case 'm':
+               sprintf(buf, "%02d", tm->tm_mon + 1);
+               break;
+       case 'M':
+               sprintf(buf, "%02d", tm->tm_min);
+               break;
+       case 'N':               /* block device name */
+               cp = strrchr(ctx->filesystem_name, '/');
+               if (cp)
+                       cp++;
+               else
+                       cp = ctx->filesystem_name;
+               append_string(s, cp, 0);
+               return;
+       case 'p':
+               sprintf(buf, "%lu", (unsigned long) getpid());
+               break;
+       case 's':
+               sprintf(buf, "%lu", (unsigned long) ctx->now);
+               break;
+       case 'S':
+               sprintf(buf, "%02d", tm->tm_sec);
+               break;
+       case 'T':
+               sprintf(buf, "%02d%02d%02d", tm->tm_hour, tm->tm_min,
+                       tm->tm_sec);
+               break;
+       case 'u':
+#ifdef TEST_PROGRAM
+               strcpy(buf, "tytso");
+               break;
+#else
+               getpwuid_r(getuid(), &pw_struct, buf, sizeof(buf), &pw);
+               if (pw)
+                       append_string(s, pw->pw_name, 0);
+               return;
+#endif
+       case 'U':
+               *flags |= FLAG_UTC;
+               return;
+       case 'y':
+               sprintf(buf, "%02d", tm->tm_year % 100);
+               break;
+       case 'Y':
+               sprintf(buf, "%d", tm->tm_year + 1900);
+               break;
+       }
+       append_string(s, buf, 0);
+}
+
+static void expand_logfn(e2fsck_t ctx, const char *log_fn, struct string *s)
+{
+       const char      *cp;
+       int             i;
+       int             flags = 0;
+
+       alloc_string(s, 100);
+       for (cp = log_fn; *cp; cp++) {
+               if (cp[0] == '%') {
+                       cp++;
+                       expand_percent_expression(ctx, *cp, s, &flags);
+                       continue;
+               }
+               for (i = 0; cp[i]; i++)
+                       if (cp[i] == '%')
+                               break;
+               append_string(s, cp, i);
+               cp += i-1;
+       }
+}
+
+static int     outbufsize;
+static void    *outbuf;
+
+static int do_read(int fd)
+{
+       int     c;
+       char            *n;
+       char    buffer[4096];
+
+       c = read(fd, buffer, sizeof(buffer)-1);
+       if (c <= 0)
+               return c;
+
+       n = realloc(outbuf, outbufsize + c);
+       if (n) {
+               outbuf = n;
+               memcpy(((char *)outbuf)+outbufsize, buffer, c);
+               outbufsize += c;
+       }
+       return c;
+}
+
+/*
+ * Fork a child process to save the output of the logfile until the
+ * appropriate file system is mounted read/write.
+ */
+static FILE *save_output(const char *s0, const char *s1, const char *s2)
+{
+       int c, fd, fds[2];
+       char *cp;
+       pid_t pid;
+       FILE *ret;
+
+       if (s0 && *s0 == 0)
+               s0 = 0;
+       if (s1 && *s1 == 0)
+               s1 = 0;
+       if (s2 && *s2 == 0)
+               s2 = 0;
+
+       /* At least one potential output file name is valid */
+       if (!s0 && !s1 && !s2)
+               return NULL;
+       if (pipe(fds) < 0) {
+               perror("pipe");
+               exit(1);
+       }
+
+       pid = fork();
+       if (pid < 0) {
+               perror("fork");
+               exit(1);
+       }
+
+       if (pid == 0) {
+               if (daemon(0, 0) < 0) {
+                       perror("daemon");
+                       exit(1);
+               }
+               /*
+                * Grab the output from our parent
+                */
+               close(fds[1]);
+               while (do_read(fds[0]) > 0)
+                       ;
+               close(fds[0]);
+
+               /* OK, now let's try to open the output file */
+               fd = -1;
+               while (1) {
+                       if (fd < 0 && s0)
+                               fd = open(s0, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+                       if (fd < 0 && s1)
+                               fd = open(s1, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+                       if (fd < 0 && s2)
+                               fd = open(s2, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+                       if (fd >= 0)
+                               break;
+                       sleep(1);
+               }
+
+               cp = outbuf;
+               while (outbufsize > 0) {
+                       c = write(fd, cp, outbufsize);
+                       if (c < 0) {
+                               if ((errno == EAGAIN) || (errno == EINTR))
+                                       continue;
+                               break;
+                       }
+                       outbufsize -= c;
+                       cp += c;
+               }
+               exit(0);
+       }
+
+       close(fds[0]);
+       ret = fdopen(fds[1], "w");
+       if (!ret)
+               close(fds[1]);
+       return ret;
+}
+
+#ifndef TEST_PROGRAM
+void set_up_logging(e2fsck_t ctx)
+{
+       struct string s, s1, s2;
+       char *s0 = 0, *log_dir = 0, *log_fn = 0;
+       int log_dir_wait = 0;
+
+       s.s = s1.s = s2.s = 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);
+       else
+               profile_get_string(ctx->profile, "options", "log_filename",
+                                  0, 0, &log_fn);
+       profile_get_string(ctx->profile, "options", "log_dir", 0, 0, &log_dir);
+
+       if (!log_fn || !log_fn[0])
+               goto out;
+
+       expand_logfn(ctx, log_fn, &s);
+       if ((log_fn[0] == '/') || !log_dir || !log_dir[0])
+               s0 = s.s;
+
+       if (log_dir && log_dir[0]) {
+               alloc_string(&s1, strlen(log_dir) + strlen(s.s) + 2);
+               append_string(&s1, log_dir, 0);
+               append_string(&s1, "/", 1);
+               append_string(&s1, s.s, 0);
+       }
+
+       free(log_dir);
+       profile_get_string(ctx->profile, "options", "log_dir_fallback", 0, 0,
+                          &log_dir);
+       if (log_dir && log_dir[0]) {
+               alloc_string(&s2, strlen(log_dir) + strlen(s.s) + 2);
+               append_string(&s2, log_dir, 0);
+               append_string(&s2, "/", 1);
+               append_string(&s2, s.s, 0);
+               printf("%s\n", s2.s);
+       }
+
+       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);
+
+out:
+       free(s.s);
+       free(s1.s);
+       free(s2.s);
+       free(log_fn);
+       free(log_dir);
+       return;
+}
+#else
+void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
+                            const char *description)
+{
+       void *ret;
+       char buf[256];
+
+       ret = malloc(size);
+       if (!ret) {
+               sprintf(buf, "Can't allocate %s\n", description);
+               exit(1);
+       }
+       memset(ret, 0, size);
+       return ret;
+}
+
+errcode_t e2fsck_allocate_context(e2fsck_t *ret)
+{
+       e2fsck_t        context;
+       errcode_t       retval;
+       char            *time_env;
+
+       context = malloc(sizeof(struct e2fsck_struct));
+       if (!context)
+               return ENOMEM;
+
+       memset(context, 0, sizeof(struct e2fsck_struct));
+
+       context->now = 1332006474;
+
+       context->filesystem_name = "/dev/sda3";
+       context->device_name = "fslabel";
+
+       *ret = context;
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       e2fsck_t        ctx;
+       struct string   s;
+
+       putenv("TZ=EST+5:00");
+       e2fsck_allocate_context(&ctx);
+       expand_logfn(ctx, "e2fsck-%N.%h.%u.%D-%T", &s);
+       printf("%s\n", s.s);
+       free(s.s);
+       expand_logfn(ctx, "e2fsck-%N.%h.%u.%Y%m%d-%H%M%S", &s);
+       printf("%s\n", s.s);
+       free(s.s);
+
+       return 0;
+}
+#endif
index 6274824..980dc4b 100644 (file)
@@ -168,7 +168,7 @@ static const char *special_inode_name[] =
  * This function does "safe" printing.  It will convert non-printable
  * ASCII characters using '^' and M- notation.
  */
-static void safe_print(const char *cp, int len)
+static void safe_print(FILE *f, const char *cp, int len)
 {
        unsigned char   ch;
 
@@ -178,14 +178,14 @@ static void safe_print(const char *cp, int len)
        while (len--) {
                ch = *cp++;
                if (ch > 128) {
-                       fputs("M-", stdout);
+                       fputs("M-", f);
                        ch -= 128;
                }
                if ((ch < 32) || (ch == 0x7f)) {
-                       fputc('^', stdout);
+                       fputc('^', f);
                        ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
                }
-               fputc(ch, stdout);
+               fputc(ch, f);
        }
 }
 
@@ -194,27 +194,28 @@ static void safe_print(const char *cp, int len)
  * This function prints a pathname, using the ext2fs_get_pathname
  * function
  */
-static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
+static void print_pathname(FILE *f, ext2_filsys fs, ext2_ino_t dir,
+                          ext2_ino_t ino)
 {
        errcode_t       retval;
        char            *path;
 
        if (!dir && (ino < num_special_inodes)) {
-               fputs(_(special_inode_name[ino]), stdout);
+               fputs(_(special_inode_name[ino]), f);
                return;
        }
 
        if (fs)
                retval = ext2fs_get_pathname(fs, dir, ino, &path);
        if (!fs || retval)
-               fputs("???", stdout);
+               fputs("???", f);
        else {
-               safe_print(path, -1);
+               safe_print(f, path, -1);
                ext2fs_free_mem(&path);
        }
 }
 
-static void print_time(time_t t)
+static void print_time(FILE *f, time_t t)
 {
        const char *            time_str;
        static int              do_gmt = -1;
@@ -229,7 +230,7 @@ static void print_time(time_t t)
                }
 #endif
                time_str = asctime((do_gmt > 0) ? gmtime(&t) : localtime(&t));
-               printf("%.24s", time_str);
+               fprintf(f, "%.24s", time_str);
 }
 
 /*
@@ -237,7 +238,7 @@ static void print_time(time_t t)
  * expansion; an @ expression can contain further '@' and '%'
  * expressions.
  */
-static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
+static _INLINE_ void expand_at_expression(FILE *f, e2fsck_t ctx, char ch,
                                          struct problem_context *pctx,
                                          int *first, int recurse)
 {
@@ -252,17 +253,17 @@ static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
                str = _(*cpp) + 1;
                if (*first && islower(*str)) {
                        *first = 0;
-                       fputc(toupper(*str++), stdout);
+                       fputc(toupper(*str++), f);
                }
-               print_e2fsck_message(ctx, str, pctx, *first, recurse+1);
+               print_e2fsck_message(f, ctx, str, pctx, *first, recurse+1);
        } else
-               printf("@%c", ch);
+               fprintf(f, "@%c", ch);
 }
 
 /*
  * This function expands '%IX' expressions
  */
-static _INLINE_ void expand_inode_expression(ext2_filsys fs, char ch,
+static _INLINE_ void expand_inode_expression(FILE *f, ext2_filsys fs, char ch,
                                             struct problem_context *ctx)
 {
        struct ext2_inode       *inode;
@@ -277,78 +278,78 @@ static _INLINE_ void expand_inode_expression(ext2_filsys fs, char ch,
        switch (ch) {
        case 's':
                if (LINUX_S_ISDIR(inode->i_mode))
-                       printf("%u", inode->i_size);
+                       fprintf(f, "%u", inode->i_size);
                else {
 #ifdef EXT2_NO_64_TYPE
                        if (inode->i_size_high)
-                               printf("0x%x%08x", inode->i_size_high,
-                                      inode->i_size);
+                               fprintf(f, "0x%x%08x", inode->i_size_high,
+                                       inode->i_size);
                        else
-                               printf("%u", inode->i_size);
+                               fprintf(f, "%u", inode->i_size);
 #else
-                       printf("%llu", EXT2_I_SIZE(inode));
+                       fprintf(f, "%llu", EXT2_I_SIZE(inode));
 #endif
                }
                break;
        case 'S':
-               printf("%u", large_inode->i_extra_isize);
+               fprintf(f, "%u", large_inode->i_extra_isize);
                break;
        case 'b':
                if (fs->super->s_feature_ro_compat &
                    EXT4_FEATURE_RO_COMPAT_HUGE_FILE) 
-                       printf("%llu", inode->i_blocks +
-                              (((long long) inode->osd2.linux2.l_i_blocks_hi)
-                               << 32));
+                       fprintf(f, "%llu", inode->i_blocks +
+                               (((long long) inode->osd2.linux2.l_i_blocks_hi)
+                                << 32));
                else
-                       printf("%u", inode->i_blocks);
+                       fprintf(f, "%u", inode->i_blocks);
                break;
        case 'l':
-               printf("%d", inode->i_links_count);
+               fprintf(f, "%d", inode->i_links_count);
                break;
        case 'm':
-               printf("0%o", inode->i_mode);
+               fprintf(f, "0%o", inode->i_mode);
                break;
        case 'M':
-               print_time(inode->i_mtime);
+               print_time(f, inode->i_mtime);
                break;
        case 'F':
-               printf("%u", inode->i_faddr);
+               fprintf(f, "%u", inode->i_faddr);
                break;
        case 'f':
-               printf("%llu", ext2fs_file_acl_block(fs, inode));
+               fprintf(f, "%llu", ext2fs_file_acl_block(fs, inode));
                break;
        case 'd':
-               printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
-                             inode->i_dir_acl : 0));
+               fprintf(f, "%u", (LINUX_S_ISDIR(inode->i_mode) ?
+                                 inode->i_dir_acl : 0));
                break;
        case 'u':
-               printf("%d", inode_uid(*inode));
+               fprintf(f, "%d", inode_uid(*inode));
                break;
        case 'g':
-               printf("%d", inode_gid(*inode));
+               fprintf(f, "%d", inode_gid(*inode));
                break;
        case 't':
                if (LINUX_S_ISREG(inode->i_mode))
-                       printf(_("regular file"));
+                       fputs(_("regular file"), f);
                else if (LINUX_S_ISDIR(inode->i_mode))
-                       printf(_("directory"));
+                       fputs(_("directory"), f);
                else if (LINUX_S_ISCHR(inode->i_mode))
-                       printf(_("character device"));
+                       fputs(_("character device"), f);
                else if (LINUX_S_ISBLK(inode->i_mode))
-                       printf(_("block device"));
+                       fputs(_("block device"), f);
                else if (LINUX_S_ISFIFO(inode->i_mode))
-                       printf(_("named pipe"));
+                       fputs(_("named pipe"), f);
                else if (LINUX_S_ISLNK(inode->i_mode))
-                       printf(_("symbolic link"));
+                       fputs(_("symbolic link"), f);
                else if (LINUX_S_ISSOCK(inode->i_mode))
-                       printf(_("socket"));
+                       fputs(_("socket"), f);
                else
-                       printf(_("unknown file type with mode 0%o"),
-                              inode->i_mode);
+                       fprintf(f, _("unknown file type with mode 0%o"),
+                               inode->i_mode);
                break;
        default:
        no_inode:
-               printf("%%I%c", ch);
+               fprintf(f, "%%I%c", ch);
                break;
        }
 }
@@ -356,7 +357,7 @@ static _INLINE_ void expand_inode_expression(ext2_filsys fs, char ch,
 /*
  * This function expands '%dX' expressions
  */
-static _INLINE_ void expand_dirent_expression(ext2_filsys fs, char ch,
+static _INLINE_ void expand_dirent_expression(FILE *f, ext2_filsys fs, char ch,
                                              struct problem_context *ctx)
 {
        struct ext2_dir_entry   *dirent;
@@ -370,34 +371,34 @@ static _INLINE_ void expand_dirent_expression(ext2_filsys fs, char ch,
 
        switch (ch) {
        case 'i':
-               printf("%u", dirent->inode);
+               fprintf(f, "%u", dirent->inode);
                break;
        case 'n':
                len = dirent->name_len & 0xFF;
                if ((ext2fs_get_rec_len(fs, dirent, &rec_len) == 0) &&
                    (len > rec_len))
                        len = rec_len;
-               safe_print(dirent->name, len);
+               safe_print(f, dirent->name, len);
                break;
        case 'r':
                (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
-               printf("%u", rec_len);
+               fprintf(f, "%u", rec_len);
                break;
        case 'l':
-               printf("%u", dirent->name_len & 0xFF);
+               fprintf(f, "%u", dirent->name_len & 0xFF);
                break;
        case 't':
-               printf("%u", dirent->name_len >> 8);
+               fprintf(f, "%u", dirent->name_len >> 8);
                break;
        default:
        no_dirent:
-               printf("%%D%c", ch);
+               fprintf(f, "%%D%c", ch);
                break;
        }
 }
 
-static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
-                                              int width, int *first,
+static _INLINE_ void expand_percent_expression(FILE *f, ext2_filsys fs,
+                                              char ch, int width, int *first,
                                               struct problem_context *ctx)
 {
        e2fsck_t e2fsck_ctx = fs ? (e2fsck_t) fs->priv_data : NULL;
@@ -408,13 +409,13 @@ static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
 
        switch (ch) {
        case '%':
-               fputc('%', stdout);
+               fputc('%', f);
                break;
        case 'b':
 #ifdef EXT2_NO_64_TYPE
-               printf("%*u", width, (unsigned long) ctx->blk);
+               fprintf(f, "%*u", width, (unsigned long) ctx->blk);
 #else
-               printf("%*llu", width, (unsigned long long) ctx->blk);
+               fprintf(f, "%*llu", width, (unsigned long long) ctx->blk);
 #endif
                break;
        case 'B':
@@ -429,98 +430,98 @@ static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
                else
                        m = _("block #");
                if (*first && islower(m[0]))
-                       fputc(toupper(*m++), stdout);
-               fputs(m, stdout);
+                       fputc(toupper(*m++), f);
+               fputs(m, f);
                if (ctx->blkcount >= 0) {
 #ifdef EXT2_NO_64_TYPE
-                       printf("%d", ctx->blkcount);
+                       fprintf(f, "%d", ctx->blkcount);
 #else
-                       printf("%lld", (long long) ctx->blkcount);
+                       fprintf(f, "%lld", (long long) ctx->blkcount);
 #endif
                }
                break;
        case 'c':
 #ifdef EXT2_NO_64_TYPE
-               printf("%*u", width, (unsigned long) ctx->blk2);
+               fprintf(f, "%*u", width, (unsigned long) ctx->blk2);
 #else
-               printf("%*llu", width, (unsigned long long) ctx->blk2);
+               fprintf(f, "%*llu", width, (unsigned long long) ctx->blk2);
 #endif
                break;
        case 'd':
-               printf("%*u", width, ctx->dir);
+               fprintf(f, "%*u", width, ctx->dir);
                break;
        case 'g':
-               printf("%*d", width, ctx->group);
+               fprintf(f, "%*d", width, ctx->group);
                break;
        case 'i':
-               printf("%*u", width, ctx->ino);
+               fprintf(f, "%*u", width, ctx->ino);
                break;
        case 'j':
-               printf("%*u", width, ctx->ino2);
+               fprintf(f, "%*u", width, ctx->ino2);
                break;
        case 'm':
-               printf("%*s", width, error_message(ctx->errcode));
+               fprintf(f, "%*s", width, error_message(ctx->errcode));
                break;
        case 'N':
 #ifdef EXT2_NO_64_TYPE
-               printf("%*u", width, ctx->num);
+               fprintf(f, "%*u", width, ctx->num);
 #else
-               printf("%*llu", width, (long long)ctx->num);
+               fprintf(f, "%*llu", width, (long long)ctx->num);
 #endif
                break;
        case 'p':
-               print_pathname(fs, ctx->ino, 0);
+               print_pathname(f, fs, ctx->ino, 0);
                break;
        case 'P':
-               print_pathname(fs, ctx->ino2,
+               print_pathname(f, fs, ctx->ino2,
                               ctx->dirent ? ctx->dirent->inode : 0);
                break;
        case 'q':
-               print_pathname(fs, ctx->dir, 0);
+               print_pathname(f, fs, ctx->dir, 0);
                break;
        case 'Q':
-               print_pathname(fs, ctx->dir, ctx->ino);
+               print_pathname(f, fs, ctx->dir, ctx->ino);
                break;
        case 'r':
 #ifdef EXT2_NO_64_TYPE
-               printf("%*d", width, ctx->blkcount);
+               fprintf(f, "%*d", width, ctx->blkcount);
 #else
-               printf("%*lld", width, (long long) ctx->blkcount);
+               fprintf(f, "%*lld", width, (long long) ctx->blkcount);
 #endif
                break;
        case 'S':
-               printf("%u", get_backup_sb(NULL, fs, NULL, NULL));
+               fprintf(f, "%u", get_backup_sb(NULL, fs, NULL, NULL));
                break;
        case 's':
-               printf("%*s", width, ctx->str ? ctx->str : "NULL");
+               fprintf(f, "%*s", width, ctx->str ? ctx->str : "NULL");
                break;
        case 't':
-               print_time((time_t) ctx->num);
+               print_time(f, (time_t) ctx->num);
                break;
        case 'T':
-               print_time(e2fsck_ctx ? e2fsck_ctx->now : time(0));
+               print_time(f, e2fsck_ctx ? e2fsck_ctx->now : time(0));
                break;
        case 'x':
-               printf("0x%0*x", width, ctx->csum1);
+               fprintf(f, "0x%0*x", width, ctx->csum1);
                break;
        case 'X':
 #ifdef EXT2_NO_64_TYPE
-               printf("0x%0*x", width, ctx->num);
+               fprintf(f, "0x%0*x", width, ctx->num);
 #else
-               printf("0x%0*llx", width, (long long)ctx->num);
+               fprintf(f, "0x%0*llx", width, (long long)ctx->num);
 #endif
                break;
        case 'y':
-               printf("0x%0*x", width, ctx->csum2);
+               fprintf(f, "0x%0*x", width, ctx->csum2);
                break;
        default:
        no_context:
-               printf("%%%c", ch);
+               fprintf(f, "%%%c", ch);
                break;
        }
 }
 
-void print_e2fsck_message(e2fsck_t ctx, const char *msg,
+void print_e2fsck_message(FILE *f, e2fsck_t ctx, const char *msg,
                          struct problem_context *pctx, int first,
                          int recurse)
 {
@@ -532,7 +533,8 @@ void print_e2fsck_message(e2fsck_t ctx, const char *msg,
        for (cp = msg; *cp; cp++) {
                if (cp[0] == '@') {
                        cp++;
-                       expand_at_expression(ctx, *cp, pctx, &first, recurse);
+                       expand_at_expression(f, ctx, *cp, pctx, &first,
+                                            recurse);
                } else if (cp[0] == '%') {
                        cp++;
                        width = 0;
@@ -542,19 +544,19 @@ void print_e2fsck_message(e2fsck_t ctx, const char *msg,
                        }
                        if (cp[0] == 'I') {
                                cp++;
-                               expand_inode_expression(fs, *cp, pctx);
+                               expand_inode_expression(f, fs, *cp, pctx);
                        } else if (cp[0] == 'D') {
                                cp++;
-                               expand_dirent_expression(fs, *cp, pctx);
+                               expand_dirent_expression(f, fs, *cp, pctx);
                        } else {
-                               expand_percent_expression(fs, *cp, width,
+                               expand_percent_expression(f, fs, *cp, width,
                                                          &first, pctx);
                        }
                } else {
                        for (i=0; cp[i]; i++)
                                if ((cp[i] == '@') || cp[i] == '%')
                                        break;
-                       printf("%.*s", i, cp);
+                       fprintf(f, "%.*s", i, cp);
                        cp += i-1;
                }
                first = 0;
index 06eb179..56d10b1 100644 (file)
@@ -1877,16 +1877,20 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
                        fflush(stdout);
                }
        }
+       message = ptr->e2p_description;
+       if (*message)
+               message = _(message);
        if (!suppress) {
-               message = ptr->e2p_description;
                if ((ctx->options & E2F_OPT_PREEN) &&
                    !(ptr->flags & PR_PREEN_NOHDR)) {
                        printf("%s: ", ctx->device_name ?
                               ctx->device_name : ctx->filesystem_name);
                }
                if (*message)
-                       print_e2fsck_message(ctx, _(message), pctx, 1, 0);
+                       print_e2fsck_message(stdout, ctx, message, pctx, 1, 0);
        }
+       if (ctx->logf && message)
+               print_e2fsck_message(ctx->logf, ctx, message, pctx, 1, 0);
        if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
                preenhalt(ctx);
 
@@ -1901,16 +1905,14 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
        } else {
                if (ptr->flags & PR_FORCE_NO) {
                        answer = 0;
-                       if (!suppress)
-                               print_answer = 1;
+                       print_answer = 1;
                } else if (ctx->options & E2F_OPT_PREEN) {
                        answer = def_yn;
                        if (!(ptr->flags & PR_PREEN_NOMSG))
                                print_answer = 1;
                } else if ((ptr->flags & PR_LATCH_MASK) &&
                           (ldesc->flags & (PRL_YES | PRL_NO))) {
-                       if (!suppress)
-                               print_answer = 1;
+                       print_answer = 1;
                        if (ldesc->flags & PRL_YES)
                                answer = 1;
                        else
@@ -1921,10 +1923,16 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
                if (!answer && !(ptr->flags & PR_NO_OK))
                        ext2fs_unmark_valid(fs);
 
-               if (print_answer)
-                       printf("%s.\n", answer ?
-                              _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
-
+               if (print_answer) {
+                       if (!suppress)
+                               printf("%s.\n", answer ?
+                                      _(preen_msg[(int) ptr->prompt]) :
+                                      _("IGNORED"));
+                       if (ctx->logf)
+                               fprintf(ctx->logf, "%s.\n", answer ?
+                                       _(preen_msg[(int) ptr->prompt]) :
+                                       _("IGNORED"));
+               }
        }
 
        if ((ptr->prompt == PROMPT_ABORT) && answer)
@@ -1955,7 +1963,7 @@ profile_get_integer(profile_t profile, const char *name, const char *subname,
        return 0;
 }
 
-void print_e2fsck_message(e2fsck_t ctx, const char *msg,
+void print_e2fsck_message(FILE *f, e2fsck_t ctx, const char *msg,
                          struct problem_context *pctx, int first,
                          int recurse)
 {
index 5c1579d..6633055 100644 (file)
@@ -1034,7 +1034,7 @@ int get_latch_flags(int mask, int *value);
 void clear_problem_context(struct problem_context *pctx);
 
 /* message.c */
-void print_e2fsck_message(e2fsck_t ctx, const char *msg,
+void print_e2fsck_message(FILE *f, e2fsck_t ctx, const char *msg,
                          struct problem_context *pctx, int first,
                          int recurse);
 
index b31a1e3..4f73a4b 100644 (file)
@@ -130,70 +130,76 @@ static void show_stats(e2fsck_t   ctx)
        frag_percent_total = (frag_percent_total + 5) / 10;
 
        if (!verbose) {
-               printf(_("%s: %u/%u files (%0d.%d%% non-contiguous), %llu/%llu blocks\n"),
-                      ctx->device_name, inodes_used, inodes,
-                      frag_percent_total / 10, frag_percent_total % 10,
-                      blocks_used, blocks);
+               log_out(ctx, _("%s: %u/%u files (%0d.%d%% non-contiguous), "
+                              "%llu/%llu blocks\n"),
+                       ctx->device_name, inodes_used, inodes,
+                       frag_percent_total / 10, frag_percent_total % 10,
+                       blocks_used, blocks);
                return;
        }
-       printf (P_("\n%8u inode used (%2.2f%%)\n", "\n%8u inodes used (%2.2f%%)\n",
-                  inodes_used), inodes_used, 100.0 * inodes_used / inodes);
-       printf (P_("%8u non-contiguous file (%0d.%d%%)\n",
-                  "%8u non-contiguous files (%0d.%d%%)\n",
-                  ctx->fs_fragmented),
+       log_out(ctx, P_("\n%8u inode used (%2.2f%%)\n",
+                       "\n%8u inodes used (%2.2f%%)\n",
+                       inodes_used), inodes_used,
+               100.0 * inodes_used / inodes);
+       log_out(ctx, P_("%8u non-contiguous file (%0d.%d%%)\n",
+                       "%8u non-contiguous files (%0d.%d%%)\n",
+                       ctx->fs_fragmented),
                ctx->fs_fragmented, frag_percent_file / 10,
                frag_percent_file % 10);
-       printf (P_("%8u non-contiguous directory (%0d.%d%%)\n",
-                  "%8u non-contiguous directories (%0d.%d%%)\n",
-                  ctx->fs_fragmented_dir),
+       log_out(ctx, P_("%8u non-contiguous directory (%0d.%d%%)\n",
+                       "%8u non-contiguous directories (%0d.%d%%)\n",
+                       ctx->fs_fragmented_dir),
                ctx->fs_fragmented_dir, frag_percent_dir / 10,
                frag_percent_dir % 10);
-       printf (_("         # of inodes with ind/dind/tind blocks: %u/%u/%u\n"),
+       log_out(ctx, _("         # of inodes with ind/dind/tind blocks: "
+                      "%u/%u/%u\n"),
                ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count);
 
        for (j=MAX_EXTENT_DEPTH_COUNT-1; j >=0; j--)
                if (ctx->extent_depth_count[j])
                        break;
        if (++j) {
-               printf (_("         Extent depth histogram: "));
+               log_out(ctx, _("         Extent depth histogram: "));
                for (i=0; i < j; i++) {
                        if (i)
                                fputc('/', stdout);
-                       printf("%u", ctx->extent_depth_count[i]);
+                       log_out(ctx, "%u", ctx->extent_depth_count[i]);
                }
-               fputc('\n', stdout);
+               log_out(ctx, "\n");
        }
 
-       printf (P_("%8llu block used (%2.2f%%)\n",
-                  "%8llu blocks used (%2.2f%%)\n",
+       log_out(ctx, P_("%8llu block used (%2.2f%%)\n",
+                       "%8llu blocks used (%2.2f%%)\n",
                   blocks_used), blocks_used, 100.0 * blocks_used / blocks);
-       printf (P_("%8u bad block\n", "%8u bad blocks\n",
-                  ctx->fs_badblocks_count), ctx->fs_badblocks_count);
-       printf (P_("%8u large file\n", "%8u large files\n",
-                  ctx->large_files), ctx->large_files);
-       printf (P_("\n%8u regular file\n", "\n%8u regular files\n",
-                  ctx->fs_regular_count), ctx->fs_regular_count);
-       printf (P_("%8u directory\n", "%8u directories\n",
-                  ctx->fs_directory_count), ctx->fs_directory_count);
-       printf (P_("%8u character device file\n",
-                  "%8u character device files\n", ctx->fs_chardev_count),
+       log_out(ctx, P_("%8u bad block\n", "%8u bad blocks\n",
+                       ctx->fs_badblocks_count), ctx->fs_badblocks_count);
+       log_out(ctx, P_("%8u large file\n", "%8u large files\n",
+                       ctx->large_files), ctx->large_files);
+       log_out(ctx, P_("\n%8u regular file\n", "\n%8u regular files\n",
+                       ctx->fs_regular_count), ctx->fs_regular_count);
+       log_out(ctx, P_("%8u directory\n", "%8u directories\n",
+                       ctx->fs_directory_count), ctx->fs_directory_count);
+       log_out(ctx, P_("%8u character device file\n",
+                       "%8u character device files\n", ctx->fs_chardev_count),
                ctx->fs_chardev_count);
-       printf (P_("%8u block device file\n", "%8u block device files\n",
-                  ctx->fs_blockdev_count), ctx->fs_blockdev_count);
-       printf (P_("%8u fifo\n", "%8u fifos\n", ctx->fs_fifo_count),
+       log_out(ctx, P_("%8u block device file\n", "%8u block device files\n",
+                       ctx->fs_blockdev_count), ctx->fs_blockdev_count);
+       log_out(ctx, P_("%8u fifo\n", "%8u fifos\n", ctx->fs_fifo_count),
                ctx->fs_fifo_count);
-       printf (P_("%8u link\n", "%8u links\n",
-                  ctx->fs_links_count - dir_links),
+       log_out(ctx, P_("%8u link\n", "%8u links\n",
+                       ctx->fs_links_count - dir_links),
                ctx->fs_links_count - dir_links);
-       printf (P_("%8u symbolic link", "%8u symbolic links",
-                  ctx->fs_symlinks_count), ctx->fs_symlinks_count);
-       printf (P_(" (%u fast symbolic link)\n", " (%u fast symbolic links)\n",
-                  ctx->fs_fast_symlinks_count), ctx->fs_fast_symlinks_count);
-       printf (P_("%8u socket\n", "%8u sockets\n", ctx->fs_sockets_count),
+       log_out(ctx, P_("%8u symbolic link", "%8u symbolic links",
+                       ctx->fs_symlinks_count), ctx->fs_symlinks_count);
+       log_out(ctx, P_(" (%u fast symbolic link)\n",
+                       " (%u fast symbolic links)\n",
+                       ctx->fs_fast_symlinks_count),
+               ctx->fs_fast_symlinks_count);
+       log_out(ctx, P_("%8u socket\n", "%8u sockets\n", ctx->fs_sockets_count),
                ctx->fs_sockets_count);
-       printf ("--------\n");
-       printf (P_("%8u file\n", "%8u files\n",
-                  ctx->fs_total_count - dir_links),
+       log_out(ctx, "--------\n");
+       log_out(ctx, P_("%8u file\n", "%8u files\n",
+                       ctx->fs_total_count - dir_links),
                ctx->fs_total_count - dir_links);
 }
 
@@ -224,19 +230,21 @@ static void check_mount(e2fsck_t ctx)
 
        if ((ctx->options & E2F_OPT_READONLY) &&
            !(ctx->options & E2F_OPT_WRITECHECK)) {
-               printf(_("Warning!  %s is mounted.\n"), ctx->filesystem_name);
+               log_out(ctx, _("Warning!  %s is mounted.\n"),
+                       ctx->filesystem_name);
                return;
        }
 
-       printf(_("%s is mounted.  "), ctx->filesystem_name);
+       log_out(ctx, _("%s is mounted.  "), ctx->filesystem_name);
        if (!ctx->interactive)
                fatal_error(ctx, _("Cannot continue, aborting.\n\n"));
        puts("\007\007\007\007");
-       printf(_("\n\nWARNING!!!  "
-              "The filesystem is mounted.   If you continue you ***WILL***\n"
-              "cause ***SEVERE*** filesystem damage.\n\n"));
+       log_out(ctx, _("\n\nWARNING!!!  "
+                      "The filesystem is mounted.   "
+                      "If you continue you ***WILL***\n"
+                      "cause ***SEVERE*** filesystem damage.\n\n"));
        puts("\007\007\007");
-       cont = ask_yn(_("Do you really want to continue"), 0);
+       cont = ask_yn(ctx, _("Do you really want to continue"), 0);
        if (!cont) {
                printf (_("check aborted.\n"));
                exit (0);
@@ -356,9 +364,9 @@ static void check_if_skip(e2fsck_t ctx)
                        reason = 0;
        }
        if (reason) {
-               fputs(ctx->device_name, stdout);
-               printf(reason, reason_arg);
-               fputs(_(", check forced.\n"), stdout);
+               log_out(ctx, "%s", ctx->device_name);
+               log_out(ctx, reason, reason_arg);
+               log_out(ctx, _(", check forced.\n"));
                return;
        }
 
@@ -391,12 +399,13 @@ static void check_if_skip(e2fsck_t ctx)
        }
 
        /* Print the summary message when we're skipping a full check */
-       printf(_("%s: clean, %u/%u files, %llu/%llu blocks"), ctx->device_name,
-              fs->super->s_inodes_count - fs->super->s_free_inodes_count,
-              fs->super->s_inodes_count,
-              ext2fs_blocks_count(fs->super) -
-              ext2fs_free_blocks_count(fs->super),
-              ext2fs_blocks_count(fs->super));
+       log_out(ctx, _("%s: clean, %u/%u files, %llu/%llu blocks"),
+               ctx->device_name,
+               fs->super->s_inodes_count - fs->super->s_free_inodes_count,
+               fs->super->s_inodes_count,
+               ext2fs_blocks_count(fs->super) -
+               ext2fs_free_blocks_count(fs->super),
+               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;
@@ -409,14 +418,14 @@ static void check_if_skip(e2fsck_t ctx)
        if (next_check <= 5) {
                if (next_check == 1) {
                        if (batt)
-                               fputs(_(" (check deferred; on battery)"),
-                                     stdout);
+                               log_out(ctx, _(" (check deferred; "
+                                              "on battery)"));
                        else
-                               fputs(_(" (check after next mount)"), stdout);
+                               log_out(ctx, _(" (check after next mount)"));
                } else
-                       printf(_(" (check in %ld mounts)"), next_check);
+                       log_out(ctx, _(" (check in %ld mounts)"), next_check);
        }
-       fputc('\n', stdout);
+       log_out(ctx, "\n");
 skip:
        ext2fs_close(fs);
        ctx->fs = NULL;
@@ -653,6 +662,12 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
                } else if (strcmp(token, "nodiscard") == 0) {
                        ctx->options &= ~E2F_OPT_DISCARD;
                        continue;
+               } else if (strcmp(token, "log_filename") == 0) {
+                       if (!arg)
+                               extended_usage++;
+                       else
+                               ctx->log_fn = string_copy(ctx, arg, 0);
+                       continue;
                } else {
                        fprintf(stderr, _("Unknown extended option: %s\n"),
                                token);
@@ -1071,8 +1086,8 @@ int e2fsck_check_mmp(ext2_filsys fs, e2fsck_t ctx)
 
        /* Print warning if e2fck will wait for more than 20 secs. */
        if (verbose || wait_time > EXT4_MMP_MIN_CHECK_INTERVAL * 4) {
-               printf("MMP interval is %u seconds and total wait time is %u "
-                      "seconds. Please wait...\n",
+               log_out(ctx, _("MMP interval is %u seconds and total wait "
+                              "time is %u seconds. Please wait...\n"),
                        mmp_check_interval, wait_time * 2);
        }
 
@@ -1157,13 +1172,25 @@ int main (int argc, char *argv[])
        }
        reserve_stdio_fds();
 
+       set_up_logging(ctx);
+       if (ctx->logf) {
+               int i;
+               fputs("E2fsck run: ", ctx->logf);
+               for (i = 0; i < argc; i++) {
+                       if (i)
+                               fputc(' ', ctx->logf);
+                       fputs(argv[i], ctx->logf);
+               }
+               fputc('\n', ctx->logf);
+       }
+
        init_resource_track(&ctx->global_rtrack, NULL);
        if (!(ctx->options & E2F_OPT_PREEN) || show_version_only)
-               fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string,
+               log_err(ctx, "e2fsck %s (%s)\n", my_ver_string,
                         my_ver_date);
 
        if (show_version_only) {
-               fprintf(stderr, _("\tUsing %s, %s\n"),
+               log_err(ctx, _("\tUsing %s, %s\n"),
                        error_message(EXT2_ET_BASE), lib_ver_date);
                exit(FSCK_OK);
        }
@@ -1214,10 +1241,10 @@ restart:
                        fs = NULL;
                }
                if (!fs || (fs->group_desc_count > 1)) {
-                       printf(_("%s: %s trying backup blocks...\n"),
-                              ctx->program_name,
-                              retval ? _("Superblock invalid,") :
-                              _("Group descriptors look bad..."));
+                       log_out(ctx, _("%s: %s trying backup blocks...\n"),
+                               ctx->program_name,
+                               retval ? _("Superblock invalid,") :
+                               _("Group descriptors look bad..."));
                        orig_superblock = ctx->superblock;
                        get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr);
                        if (fs)
@@ -1227,10 +1254,13 @@ restart:
                        if ((orig_retval == 0) && retval != 0) {
                                if (fs)
                                        ext2fs_close(fs);
-                               com_err(ctx->program_name, retval,
-                                       "when using the backup blocks");
-                               printf(_("%s: going back to original "
-                                        "superblock\n"), ctx->program_name);
+                               log_out(ctx, _("%s: %s while using the "
+                                              "backup blocks"),
+                                       ctx->program_name,
+                                       error_message(retval));
+                               log_out(ctx, _("%s: going back to original "
+                                              "superblock\n"),
+                                       ctx->program_name);
                                ctx->superblock = orig_superblock;
                                retval = try_open_fs(ctx, flags, io_ptr, &fs);
                        }
@@ -1256,30 +1286,32 @@ failure:
                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 "
+                       log_out(ctx, _("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"));
+                       log_out(ctx, _("Could this be a zero-length "
+                                      "partition?\n"));
                else if ((retval == EPERM) || (retval == EACCES))
-                       printf(_("You must have %s access to the "
+                       log_out(ctx, _("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"));
+                       log_out(ctx, _("Possibly non-existent or "
+                                      "swap device?\n"));
                else if (retval == EBUSY)
-                       printf(_("Filesystem mounted or opened exclusively "
-                                "by another program?\n"));
+                       log_out(ctx, _("Filesystem mounted or opened "
+                                "exclusively by another program?\n"));
                else if (retval == ENOENT)
-                       printf(_("Possibly non-existent device?\n"));
+                       log_out(ctx, _("Possibly non-existent 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"));
+                       log_out(ctx, _("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);
@@ -1336,6 +1368,7 @@ failure:
        fs->priv_data = ctx;
        fs->now = ctx->now;
        sb = fs->super;
+
        if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
                com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH,
                        _("while trying to open %s"),
@@ -1377,6 +1410,10 @@ failure:
                goto restart;
        }
 
+       if (ctx->logf)
+               fprintf(ctx->logf, "Filesystem UUID: %s\n",
+                       e2p_uuid2str(sb->s_uuid));
+
        if ((ctx->mount_flags & EXT2_MF_MOUNTED) &&
            !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER))
                goto skip_journal;
@@ -1398,9 +1435,9 @@ failure:
         */
        if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
                if (ctx->options & E2F_OPT_READONLY) {
-                       printf(_("Warning: skipping journal recovery "
-                                "because doing a read-only filesystem "
-                                "check.\n"));
+                       log_out(ctx, _("Warning: skipping journal recovery "
+                                      "because doing a read-only filesystem "
+                                      "check.\n"));
                        io_channel_flush(ctx->fs->io);
                } else {
                        if (ctx->flags & E2F_FLAG_RESTARTED) {
@@ -1442,30 +1479,30 @@ print_unsupp_features:
                int     i, j;
                __u32   *mask = features, m;
 
-               fprintf(stderr, _("%s has unsupported feature(s):"),
+               log_err(ctx, _("%s has unsupported feature(s):"),
                        ctx->filesystem_name);
 
                for (i=0; i <3; i++,mask++) {
                        for (j=0,m=1; j < 32; j++, m<<=1) {
                                if (*mask & m)
-                                       fprintf(stderr, " %s",
+                                       log_err(ctx, " %s",
                                                e2p_feature2string(i, m));
                        }
                }
-               putc('\n', stderr);
+               log_err(ctx, "\n");
                goto get_newer;
        }
 #ifdef ENABLE_COMPRESSION
        if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION)
-               com_err(ctx->program_name, 0,
-                       _("Warning: compression support is experimental.\n"));
+               log_err(ctx, _("%s: warning: compression support "
+                              "is experimental.\n"),
+                       ctx->program_name);
 #endif
 #ifndef ENABLE_HTREE
        if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
-               com_err(ctx->program_name, 0,
-                       _("E2fsck not compiled with HTREE support,\n\t"
+               log_err(ctx, _("%s: e2fsck not compiled with HTREE support,\n\t"
                          "but filesystem %s has HTREE directories.\n"),
-                       ctx->device_name);
+                       ctx->program_name, ctx->device_name);
                goto get_newer;
        }
 #endif
@@ -1515,11 +1552,11 @@ print_unsupp_features:
 
        retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
        if (retval) {
-               com_err(ctx->program_name, retval,
-                       _("while reading bad blocks inode"));
+               log_out(ctx, _("%s: %s while reading bad blocks inode\n"),
+                       ctx->program_name, error_message(retval));
                preenhalt(ctx);
-               printf(_("This doesn't bode well,"
-                        but we'll try to go on...\n"));
+               log_out(ctx, _("This doesn't bode well, "
+                              "but we'll try to go on...\n"));
        }
 
        /*
@@ -1556,22 +1593,22 @@ print_unsupp_features:
                                fs->super->s_feature_compat &=
                                        ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
                                fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
-                               com_err(ctx->program_name, 0,
-                                       _("Couldn't determine journal size"));
+                               log_out(ctx, "%s: Couldn't determine "
+                                       "journal size\n", ctx->program_name);
                                goto no_journal;
                        }
-                       printf(_("Creating journal (%d blocks): "),
+                       log_out(ctx, _("Creating journal (%d blocks): "),
                               journal_size);
                        fflush(stdout);
                        retval = ext2fs_add_journal_inode(fs,
                                                          journal_size, 0);
                        if (retval) {
-                               com_err("Error ", retval,
-                                       _("\n\twhile trying to create journal"));
+                               log_out(ctx, "%s: while trying to create "
+                                       "journal\n", error_message(retval));
                                goto no_journal;
                        }
-                       printf(_(" Done.\n"));
-                       printf(_("\n*** journal has been re-created - "
+                       log_out(ctx, _(" Done.\n"));
+                       log_out(ctx, _("\n*** journal has been re-created - "
                                       "filesystem is now ext3 again ***\n"));
                }
        }
@@ -1583,7 +1620,7 @@ no_journal:
        }
 
        if (run_result == E2F_FLAG_RESTART) {
-               printf(_("Restarting e2fsck from the beginning...\n"));
+               log_out(ctx, _("Restarting e2fsck from the beginning...\n"));
                retval = e2fsck_reset_context(ctx);
                if (retval) {
                        com_err(ctx->program_name, retval,
@@ -1594,8 +1631,8 @@ no_journal:
                goto restart;
        }
        if (run_result & E2F_FLAG_CANCEL) {
-               printf(_("%s: e2fsck canceled.\n"), ctx->device_name ?
-                      ctx->device_name : ctx->filesystem_name);
+               log_out(ctx, _("%s: e2fsck canceled.\n"), ctx->device_name ?
+                       ctx->device_name : ctx->filesystem_name);
                exit_value |= FSCK_CANCELED;
        }
        if (run_result & E2F_FLAG_ABORT)
@@ -1611,19 +1648,20 @@ no_journal:
        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);
+                       log_out(ctx, _("\n%s: ***** FILE SYSTEM WAS "
+                                      "MODIFIED *****\n"),
+                               ctx->device_name);
                if (ctx->mount_flags & EXT2_MF_ISROOT) {
-                       printf(_("%s: ***** REBOOT LINUX *****\n"),
-                              ctx->device_name);
+                       log_out(ctx, _("%s: ***** REBOOT LINUX *****\n"),
+                               ctx->device_name);
                        exit_value |= FSCK_REBOOT;
                }
        }
        if (!ext2fs_test_valid(fs) ||
            ((exit_value & FSCK_CANCELED) &&
             (sb->s_state & EXT2_ERROR_FS))) {
-               printf(_("\n%s: ********** WARNING: Filesystem still has "
-                        "errors **********\n\n"), ctx->device_name);
+               log_out(ctx, _("\n%s: ********** WARNING: Filesystem still has "
+                              "errors **********\n\n"), ctx->device_name);
                exit_value |= FSCK_UNCORRECTED;
                exit_value &= ~FSCK_NONDESTRUCT;
        }
index 6e3a1dc..7c4caab 100644 (file)
@@ -41,6 +41,7 @@
 
 extern e2fsck_t e2fsck_global_ctx;   /* Try your very best not to use this! */
 
+#include <stdarg.h>
 #include <time.h>
 #include <sys/time.h>
 #include <sys/resource.h>
@@ -59,18 +60,18 @@ void fatal_error(e2fsck_t ctx, const char *msg)
                if (ctx->fs->io->magic == EXT2_ET_MAGIC_IO_CHANNEL)
                        io_channel_flush(ctx->fs->io);
                else
-                       fprintf(stderr, "e2fsck: io manager magic bad!\n");
+                       log_err(ctx, "e2fsck: io manager magic bad!\n");
        }
        if (ext2fs_test_changed(fs)) {
                exit_value |= FSCK_NONDESTRUCT;
-               printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
+               log_out(ctx, _("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"),
                        ctx->device_name);
                if (ctx->mount_flags & EXT2_MF_ISROOT)
                        exit_value |= FSCK_REBOOT;
        }
        if (!ext2fs_test_valid(fs)) {
-               printf(_("\n%s: ********** WARNING: Filesystem still has "
-                        "errors **********\n\n"), ctx->device_name);
+               log_out(ctx, _("\n%s: ********** WARNING: Filesystem still has "
+                              "errors **********\n\n"), ctx->device_name);
                exit_value |= FSCK_UNCORRECTED;
                exit_value &= ~FSCK_NONDESTRUCT;
        }
@@ -81,6 +82,34 @@ out:
        exit(exit_value);
 }
 
+void log_out(e2fsck_t ctx, const char *fmt, ...)
+{
+       va_list pvar;
+
+       va_start(pvar, fmt);
+       vprintf(fmt, pvar);
+       va_end(pvar);
+       if (ctx->logf) {
+               va_start(pvar, fmt);
+               vfprintf(ctx->logf, fmt, pvar);
+               va_end(pvar);
+       }
+}
+
+void log_err(e2fsck_t ctx, const char *fmt, ...)
+{
+       va_list pvar;
+
+       va_start(pvar, fmt);
+       vfprintf(stderr, fmt, pvar);
+       va_end(pvar);
+       if (ctx->logf) {
+               va_start(pvar, fmt);
+               vfprintf(ctx->logf, fmt, pvar);
+               va_end(pvar);
+       }
+}
+
 void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
                             const char *description)
 {
@@ -153,7 +182,7 @@ static int read_a_char(void)
 }
 #endif
 
-int ask_yn(const char * string, int def)
+int ask_yn(e2fsck_t ctx, const char * string, int def)
 {
        int             c;
        const char      *defstr;
@@ -177,7 +206,7 @@ int ask_yn(const char * string, int def)
                defstr = _(_("<n>"));
        else
                defstr = _(" (y/n)");
-       printf("%s%s? ", string, defstr);
+       log_out(ctx, "%s%s? ", string, defstr);
        while (1) {
                fflush (stdout);
                if ((c = read_a_char()) == EOF)
@@ -186,12 +215,11 @@ int ask_yn(const char * string, int def)
 #ifdef HAVE_TERMIOS_H
                        tcsetattr (0, TCSANOW, &termios);
 #endif
-                       if (e2fsck_global_ctx &&
-                           e2fsck_global_ctx->flags & E2F_FLAG_SETJMP_OK) {
-                               puts("\n");
+                       if (ctx->flags & E2F_FLAG_SETJMP_OK) {
+                               log_out(ctx, "\n");
                                longjmp(e2fsck_global_ctx->abort_loc, 1);
                        }
-                       puts(_("cancelled!\n"));
+                       log_out(ctx, _("cancelled!\n"));
                        return 0;
                }
                if (strchr(short_yes, (char) c)) {
@@ -206,9 +234,9 @@ int ask_yn(const char * string, int def)
                        break;
        }
        if (def)
-               puts(_("yes\n"));
+               log_out(ctx, _("yes\n"));
        else
-               puts (_("no\n"));
+               log_out(ctx, _("no\n"));
 #ifdef HAVE_TERMIOS_H
        tcsetattr (0, TCSANOW, &termios);
 #endif
@@ -218,18 +246,18 @@ int ask_yn(const char * string, int def)
 int ask (e2fsck_t ctx, const char * string, int def)
 {
        if (ctx->options & E2F_OPT_NO) {
-               printf (_("%s? no\n\n"), string);
+               log_out(ctx, _("%s? no\n\n"), string);
                return 0;
        }
        if (ctx->options & E2F_OPT_YES) {
-               printf (_("%s? yes\n\n"), string);
+               log_out(ctx, _("%s? yes\n\n"), string);
                return 1;
        }
        if (ctx->options & E2F_OPT_PREEN) {
-               printf ("%s? %s\n\n", string, def ? _("yes") : _("no"));
+               log_out(ctx, "%s? %s\n\n", string, def ? _("yes") : _("no"));
                return def;
        }
-       return ask_yn(string, def);
+       return ask_yn(ctx, string, def);
 }
 
 void e2fsck_read_bitmaps(e2fsck_t ctx)
@@ -283,7 +311,7 @@ void preenhalt(e2fsck_t ctx)
 
        if (!(ctx->options & E2F_OPT_PREEN))
                return;
-       fprintf(stderr, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
+       log_err(ctx, _("\n\n%s: UNEXPECTED INCONSISTENCY; "
                "RUN fsck MANUALLY.\n\t(i.e., without -a or -p options)\n"),
               ctx->device_name);
        ctx->flags |= E2F_FLAG_EXITING;
@@ -358,30 +386,30 @@ void print_resource_track(e2fsck_t ctx, const char *desc,
        gettimeofday(&time_end, 0);
 
        if (desc)
-               printf("%s: ", desc);
+               log_out(ctx, "%s: ", desc);
 
 #ifdef HAVE_MALLINFO
 #define kbytes(x)      (((unsigned long)(x) + 1023) / 1024)
 
        malloc_info = mallinfo();
-       printf(_("Memory used: %luk/%luk (%luk/%luk), "),
-              kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
-              kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
+       log_out(ctx, _("Memory used: %luk/%luk (%luk/%luk), "),
+               kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
+               kbytes(malloc_info.uordblks), kbytes(malloc_info.fordblks));
 #else
-       printf(_("Memory used: %lu, "),
-              (unsigned long) (((char *) sbrk(0)) - 
-                               ((char *) track->brk_start)));
+       log_out(ctx, _("Memory used: %lu, "),
+               (unsigned long) (((char *) sbrk(0)) -
+                                ((char *) track->brk_start)));
 #endif
 #ifdef HAVE_GETRUSAGE
        getrusage(RUSAGE_SELF, &r);
 
-       printf(_("time: %5.2f/%5.2f/%5.2f\n"),
-              timeval_subtract(&time_end, &track->time_start),
-              timeval_subtract(&r.ru_utime, &track->user_start),
-              timeval_subtract(&r.ru_stime, &track->system_start));
+       log_out(ctx, _("time: %5.2f/%5.2f/%5.2f\n"),
+               timeval_subtract(&time_end, &track->time_start),
+               timeval_subtract(&r.ru_utime, &track->user_start),
+               timeval_subtract(&r.ru_stime, &track->system_start));
 #else
-       printf(_("elapsed time: %6.3f\n"),
-              timeval_subtract(&time_end, &track->time_start));
+       log_out(ctx, _("elapsed time: %6.3f\n"),
+               timeval_subtract(&time_end, &track->time_start));
 #endif
 #define mbytes(x)      (((x) + 1048575) / 1048576)
        if (channel && channel->manager && channel->manager->get_stats) {
@@ -390,7 +418,7 @@ void print_resource_track(e2fsck_t ctx, const char *desc,
                unsigned long long bytes_written = 0;
 
                if (desc)
-                       printf("%s: ", desc);
+                       log_out(ctx, "%s: ", desc);
 
                channel->manager->get_stats(channel, &delta);
                if (delta) {
@@ -398,10 +426,11 @@ void print_resource_track(e2fsck_t ctx, const char *desc,
                        bytes_written = delta->bytes_written -
                                track->bytes_written;
                }
-               printf("I/O read: %lluMB, write: %lluMB, rate: %.2fMB/s\n",
-                      mbytes(bytes_read), mbytes(bytes_written),
-                      (double)mbytes(bytes_read + bytes_written) /
-                      timeval_subtract(&time_end, &track->time_start));
+               log_out(ctx, "I/O read: %lluMB, write: %lluMB, "
+                       "rate: %.2fMB/s\n",
+                       mbytes(bytes_read), mbytes(bytes_written),
+                       (double)mbytes(bytes_read + bytes_written) /
+                       timeval_subtract(&time_end, &track->time_start));
        }
 }
 #endif /* RESOURCE_TRACK */