[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit
Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/Makefile.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/Makefile.in
new file mode 100644
index 0000000..553c361
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/Makefile.in
@@ -0,0 +1,712 @@
+#
+# Standard e2fsprogs prologue....
+#
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+top_builddir = ..
+my_dir = misc
+INSTALL = @INSTALL@
+
+@MCONFIG@
+
+@DEFRAG_CMT@@LINUX_CMT@E4DEFRAG_PROG= e4defrag
+@DEFRAG_CMT@@LINUX_CMT@E4DEFRAG_MAN= e4defrag.8
+
+@IMAGER_CMT@E2IMAGE_PROG= e2image
+@IMAGER_CMT@E2IMAGE_MAN= e2image.8
+
+@UUIDD_CMT@UUIDD_PROG= uuidd
+@UUIDD_CMT@UUIDD_MAN= uuidd.8
+
+@BLKID_CMT@BLKID_PROG= blkid
+@BLKID_CMT@BLKID_MAN= blkid.8
+
+@BLKID_CMT@FINDFS_LINK= findfs
+@BLKID_CMT@FINDFS_MAN= findfs.8
+
+SPROGS= mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \
+ $(E2IMAGE_PROG) @FSCK_PROG@ e2undo
+USPROGS= mklost+found filefrag e2freefrag $(UUIDD_PROG) $(E4DEFRAG_PROG)
+SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
+ e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \
+ logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \
+ $(UUIDD_MAN) $(E4DEFRAG_MAN) @FSCK_MAN@
+FMANPAGES= mke2fs.conf.5 ext4.5
+
+UPROGS= chattr lsattr @UUID_CMT@ uuidgen
+UMANPAGES= chattr.1 lsattr.1 @UUID_CMT@ uuidgen.1
+
+LPROGS= @E2INITRD_PROG@
+
+TUNE2FS_OBJS= tune2fs.o util.o
+MKLPF_OBJS= mklost+found.o
+MKE2FS_OBJS= mke2fs.o util.o profile.o prof_err.o default_profile.o
+CHATTR_OBJS= chattr.o
+LSATTR_OBJS= lsattr.o
+UUIDGEN_OBJS= uuidgen.o
+UUIDD_OBJS= uuidd.o
+DUMPE2FS_OBJS= dumpe2fs.o
+BADBLOCKS_OBJS= badblocks.o
+E2IMAGE_OBJS= e2image.o
+FSCK_OBJS= fsck.o base_device.o ismounted.o
+BLKID_OBJS= blkid.o
+FILEFRAG_OBJS= filefrag.o
+E2UNDO_OBJS= e2undo.o
+E4DEFRAG_OBJS= e4defrag.o
+E2FREEFRAG_OBJS= e2freefrag.o
+
+PROFILED_TUNE2FS_OBJS= profiled/tune2fs.o profiled/util.o
+PROFILED_MKLPF_OBJS= profiled/mklost+found.o
+PROFILED_MKE2FS_OBJS= profiled/mke2fs.o profiled/util.o profiled/profile.o \
+ profiled/prof_err.o profiled/default_profile.o
+PROFILED_CHATTR_OBJS= profiled/chattr.o
+PROFILED_LSATTR_OBJS= profiled/lsattr.o
+PROFILED_UUIDGEN_OBJS= profiled/uuidgen.o
+PROFILED_UUIDD_OBJS= profiled/uuidd.o
+PROFILED_DUMPE2FS_OBJS= profiled/dumpe2fs.o
+PROFILED_BADBLOCKS_OBJS= profiled/badblocks.o
+PROFILED_E2IMAGE_OBJS= profiled/e2image.o
+PROFILED_FSCK_OBJS= profiled/fsck.o profiled/base_device.o \
+ profiled/ismounted.o
+PROFILED_BLKID_OBJS= profiled/blkid.o
+PROFILED_FILEFRAG_OBJS= profiled/filefrag.o
+PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o
+PROFILED_E2UNDO_OBJS= profiled/e2undo.o
+PROFILED_E4DEFRAG_OBJS= profiled/e4defrag.o
+
+SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c \
+ $(srcdir)/chattr.c $(srcdir)/lsattr.c $(srcdir)/dumpe2fs.c \
+ $(srcdir)/badblocks.c $(srcdir)/fsck.c $(srcdir)/util.c \
+ $(srcdir)/uuidgen.c $(srcdir)/blkid.c $(srcdir)/logsave.c \
+ $(srcdir)/filefrag.c $(srcdir)/base_device.c \
+ $(srcdir)/ismounted.c $(srcdir)/../e2fsck/profile.c \
+ $(srcdir)/e2undo.c $(srcdir)/e2freefrag.c
+
+LIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
+DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR)
+PROFILED_LIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR)
+PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(DEPPROFILED_LIBCOM_ERR)
+
+STATIC_LIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR)
+STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
+
+LIBS_E2P= $(LIBE2P) $(LIBCOM_ERR)
+DEPLIBS_E2P= $(LIBE2P) $(DEPLIBCOM_ERR)
+
+COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree
+
+.c.o:
+ $(E) " CC $<"
+ $(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@
+ $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+@PROFILE_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
+
+all:: profiled $(SPROGS) $(UPROGS) $(USPROGS) $(SMANPAGES) $(UMANPAGES) \
+ $(FMANPAGES) $(LPROGS) $(E4DEFRAG_PROG)
+
+@PROFILE_CMT@all:: tune2fs.profiled blkid.profiled e2image.profiled \
+ e2undo.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \
+ logsave.profiled filefrag.profiled uuidgen.profiled uuidd.profiled \
+ e2image.profiled e4defrag.profiled e2freefrag.profiled
+
+profiled:
+@PROFILE_CMT@ $(E) " MKDIR $@"
+@PROFILE_CMT@ $(Q) mkdir profiled
+
+prof_err.c prof_err.h: $(srcdir)/../e2fsck/prof_err.et
+ $(E) " COMPILE_ET prof_err.et"
+ $(Q) $(COMPILE_ET) $(srcdir)/../e2fsck/prof_err.et
+
+profile.h: $(top_srcdir)/e2fsck/profile.h
+ $(E) " CP $<"
+ $(Q) cp $< $@
+
+mke2fs.conf: $(srcdir)/mke2fs.conf.in
+ if test -f $(srcdir)/mke2fs.conf.custom.in ; then \
+ cp $(srcdir)/mke2fs.conf.custom.in mke2fs.conf; \
+ else \
+ cp $(srcdir)/mke2fs.conf.in mke2fs.conf; \
+ fi
+
+default_profile.c: mke2fs.conf $(srcdir)/profile-to-c.awk
+ $(E) " PROFILE_TO_C mke2fs.conf"
+ $(Q) $(AWK) -f $(srcdir)/profile-to-c.awk < mke2fs.conf \
+ > default_profile.c
+profile.o:
+ $(E) " CC $<"
+ $(Q) $(CC) -c $(ALL_CFLAGS) $(srcdir)/../e2fsck/profile.c -o $@
+@PROFILE_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/profile.o -c \
+@PROFILE_CMT@ $(srcdir)/../e2fsck/profile.c
+
+findsuper: findsuper.o
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o findsuper findsuper.o $(LIBS)
+
+partinfo: partinfo.o
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o partinfo partinfo.o
+
+e2initrd_helper: e2initrd_helper.o $(DEPLIBS) $(DEPLIBBLKID) $(LIBEXT2FS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o e2initrd_helper e2initrd_helper.o $(LIBS) \
+ $(LIBBLKID) $(LIBEXT2FS) $(LIBINTL)
+
+tune2fs: $(TUNE2FS_OBJS) $(DEPLIBS) $(DEPLIBS_E2P) $(DEPLIBBLKID) \
+ $(DEPLIBUUID) $(DEPLIBQUOTA) $(LIBEXT2FS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o tune2fs $(TUNE2FS_OBJS) $(LIBS) \
+ $(LIBBLKID) $(LIBUUID) $(LIBQUOTA) $(LIBEXT2FS) $(LIBS_E2P) \
+ $(LIBINTL)
+
+tune2fs.static: $(TUNE2FS_OBJS) $(STATIC_DEPLIBS) $(STATIC_LIBE2P) $(DEPSTATIC_LIBBLKID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(LDFLAGS_STATIC) -o tune2fs.static $(TUNE2FS_OBJS) \
+ $(STATIC_LIBS) $(STATIC_LIBBLKID) $(STATIC_LIBUUID) \
+ $(STATIC_LIBQUOTA) $(STATIC_LIBE2P) $(LIBINTL)
+
+tune2fs.profiled: $(TUNE2FS_OBJS) $(PROFILED_DEPLIBS) \
+ $(PROFILED_E2P) $(DEPPROFILED_LIBBLKID) $(DEPPROFILED_LIBUUID) \
+ $(DEPPROFILED_LIBQUOTA)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o tune2fs.profiled \
+ $(PROFILED_TUNE2FS_OBJS) $(PROFILED_LIBBLKID) \
+ $(PROFILED_LIBUUID) $(PROFILED_LIBQUOTA) $(PROFILED_LIBE2P) \
+ $(LIBINTL) $(PROFILED_LIBS)
+
+blkid: $(BLKID_OBJS) $(DEPLIBBLKID) $(LIBEXT2FS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o blkid $(BLKID_OBJS) $(LIBBLKID) $(LIBINTL) \
+ $(LIBEXT2FS)
+
+blkid.static: $(BLKID_OBJS) $(STATIC_DEPLIBS) $(DEPSTATIC_LIBBLKID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o blkid.static $(BLKID_OBJS) $(STATIC_LIBS) \
+ $(STATIC_LIBBLKID) $(LIBINTL)
+
+blkid.profiled: $(BLKID_OBJS) $(DEPPROFILED_LIBBLKID) \
+ $(PROFILED_LIBEXT2FS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o blkid.profiled $(PROFILED_BLKID_OBJS) \
+ $(PROFILED_LIBBLKID) $(LIBINTL) $(PROFILED_LIBEXT2FS)
+
+e2image: $(E2IMAGE_OBJS) $(DEPLIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o e2image $(E2IMAGE_OBJS) $(LIBS) $(LIBINTL)
+
+e2image.profiled: $(E2IMAGE_OBJS) $(PROFILED_DEPLIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2image.profiled \
+ $(PROFILED_E2IMAGE_OBJS) $(PROFILED_LIBS) $(LIBINTL)
+
+e2undo: $(E2UNDO_OBJS) $(DEPLIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o e2undo $(E2UNDO_OBJS) $(LIBS) $(LIBINTL)
+
+e2undo.profiled: $(E2UNDO_OBJS) $(PROFILED_DEPLIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2undo.profiled \
+ $(PROFILED_E2UNDO_OBJS) $(PROFILED_LIBS) $(LIBINTL)
+
+e4defrag: $(E4DEFRAG_OBJS) $(DEPLIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o e4defrag $(E4DEFRAG_OBJS) $(LIBS)
+
+e4defrag.profiled: $(E4DEFRAG_OBJS) $(PROFILED_DEPLIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e4defrag.profiled \
+ $(PROFILED_E4DEFRAG_OBJS) $(PROFILED_LIBS)
+
+base_device: base_device.c
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(srcdir)/base_device.c \
+ -DDEBUG -o base_device
+
+check:: base_device
+ ./base_device < $(srcdir)/base_device.tst > base_device.out
+ cmp $(srcdir)/base_device.tst base_device.out
+
+mklost+found: $(MKLPF_OBJS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o mklost+found $(MKLPF_OBJS) $(LIBINTL)
+
+mke2fs: $(MKE2FS_OBJS) $(DEPLIBS) $(LIBE2P) $(DEPLIBBLKID) $(DEPLIBUUID) \
+ $(DEPLIBQUOTA) $(LIBEXT2FS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o mke2fs $(MKE2FS_OBJS) $(LIBS) $(LIBBLKID) \
+ $(LIBUUID) $(LIBQUOTA) $(LIBEXT2FS) $(LIBE2P) $(LIBINTL)
+
+mke2fs.static: $(MKE2FS_OBJS) $(STATIC_DEPLIBS) $(STATIC_LIBE2P) $(DEPSTATIC_LIBUUID) \
+ $(DEPSTATIC_LIBQUOTA) $(DEPSTATIC_LIBBLKID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -static -o mke2fs.static $(MKE2FS_OBJS) \
+ $(STATIC_LIBQUOTA) $(STATIC_LIBS) $(STATIC_LIBE2P) \
+ $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL)
+
+mke2fs.profiled: $(MKE2FS_OBJS) $(PROFILED_DEPLIBS) \
+ $(PROFILED_LIBE2P) $(PROFILED_DEPLIBBLKID) $(PROFILED_DEPLIBUUID) \
+ $(PROFILED_LIBQUOTA)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o mke2fs.profiled \
+ $(PROFILED_MKE2FS_OBJS) $(PROFILED_LIBBLKID) \
+ $(PROFILED_LIBUUID) $(PROFILED_LIBQUOTA) $(PROFILED_LIBE2P) $(LIBINTL) \
+ $(PROFILED_LIBS)
+
+chattr: $(CHATTR_OBJS) $(DEPLIBS_E2P)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o chattr $(CHATTR_OBJS) $(LIBS_E2P) $(LIBINTL)
+
+lsattr: $(LSATTR_OBJS) $(DEPLIBS_E2P)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o lsattr $(LSATTR_OBJS) $(LIBS_E2P) $(LIBINTL)
+
+uuidgen: $(UUIDGEN_OBJS) $(DEPLIBUUID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o uuidgen $(UUIDGEN_OBJS) $(LIBUUID) $(LIBINTL)
+
+uuidgen.profiled: $(UUIDGEN_OBJS) $(PROFILED_DEPLIBUUID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o uuidgen.profiled \
+ $(PROFILED_UUIDGEN_OBJS) $(PROFILED_LIBUUID) $(LIBINTL)
+
+uuidd: $(UUIDD_OBJS) $(DEPLIBUUID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o uuidd $(UUIDD_OBJS) $(LIBUUID) $(LIBINTL)
+
+uuidd.profiled: $(UUIDD_OBJS) $(PROFILED_DEPLIBUUID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o uuidd.profiled $(PROFILED_UUIDD_OBJS) \
+ $(PROFILED_LIBUUID) $(LIBINTL)
+
+dumpe2fs: $(DUMPE2FS_OBJS) $(DEPLIBS) $(DEPLIBS_E2P) $(DEPLIBUUID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o dumpe2fs $(DUMPE2FS_OBJS) $(LIBS) \
+ $(LIBS_E2P) $(LIBUUID) $(LIBINTL)
+
+dumpe2fs.profiled: $(DUMPE2FS_OBJS) $(PROFILED_DEPLIBS) \
+ $(PROFILED_LIBE2P) $(PROFILED_DEPLIBUUID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o dumpe2fs.profiled \
+ $(PROFILED_DUMPE2FS_OBJS) $(PROFILED_LIBS) \
+ $(PROFILED_LIBE2P) $(PROFILED_LIBUUID) $(LIBINTL)
+
+fsck: $(FSCK_OBJS) $(DEPLIBBLKID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o fsck $(FSCK_OBJS) $(LIBBLKID) $(LIBINTL)
+
+fsck.profiled: $(FSCK_OBJS) $(PROFILED_DEPLIBBLKID)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o fsck.profiled $(PROFILED_FSCK_OBJS) \
+ $(PROFILED_LIBBLKID) $(LIBINTL)
+
+badblocks: $(BADBLOCKS_OBJS) $(DEPLIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o badblocks $(BADBLOCKS_OBJS) $(LIBS) $(LIBINTL)
+
+badblocks.profiled: $(BADBLOCKS_OBJS) $(PROFILED_DEPLIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o badblocks.profiled \
+ $(PROFILED_BADBLOCKS_OBJS) $(PROFILED_LIBS) $(LIBINTL)
+
+logsave: logsave.o
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o logsave logsave.o
+
+logsave.profiled: logsave.o
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o logsave.profiled profiled/logsave.o
+
+e2freefrag: $(E2FREEFRAG_OBJS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o e2freefrag $(E2FREEFRAG_OBJS) $(LIBS)
+
+e2freefrag.profiled: $(E2FREEFRAG_OBJS) $(PROFILED_DEPLIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2freefrag.profiled \
+ $(PROFILED_E2FREEFRAG_OBJS) $(PROFILED_LIBS)
+
+filefrag: $(FILEFRAG_OBJS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o filefrag $(FILEFRAG_OBJS)
+
+filefrag.profiled: $(FILEFRAG_OBJS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o filefrag.profiled \
+ $(PROFILED_FILEFRAG_OBJS)
+
+tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
+ $(E) " LD $@"
+ $(CC) -o tst_ismounted $(srcdir)/ismounted.c -DDEBUG $(ALL_CFLAGS) \
+ $(LIBCOM_ERR)
+
+tune2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/tune2fs.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/tune2fs.8.in tune2fs.8
+
+mklost+found.8: $(DEP_SUBSTITUTE) $(srcdir)/mklost+found.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/mklost+found.8.in mklost+found.8
+
+mke2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/mke2fs.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/mke2fs.8.in mke2fs.8
+
+mke2fs.conf.5: $(DEP_SUBSTITUTE) $(srcdir)/mke2fs.conf.5.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/mke2fs.conf.5.in mke2fs.conf.5
+
+ext4.5: $(DEP_SUBSTITUTE) $(srcdir)/ext4.5.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/$@.in $@
+
+e2label.8: $(DEP_SUBSTITUTE) $(srcdir)/e2label.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2label.8.in e2label.8
+
+e2undo.8: $(DEP_SUBSTITUTE) $(srcdir)/e2undo.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2undo.8.in e2undo.8
+
+findfs.8: $(DEP_SUBSTITUTE) $(srcdir)/findfs.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/findfs.8.in findfs.8
+
+e2image.8: $(DEP_SUBSTITUTE) $(srcdir)/e2image.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2image.8.in e2image.8
+
+e4defrag.8: $(DEP_SUBSTITUTE) $(srcdir)/e4defrag.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e4defrag.8.in e4defrag.8
+
+dumpe2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/dumpe2fs.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/dumpe2fs.8.in dumpe2fs.8
+
+badblocks.8: $(DEP_SUBSTITUTE) $(srcdir)/badblocks.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/badblocks.8.in badblocks.8
+
+fsck.8: $(DEP_SUBSTITUTE) $(srcdir)/fsck.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/fsck.8.in fsck.8
+
+blkid.8: $(DEP_SUBSTITUTE) $(srcdir)/blkid.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/blkid.8.in blkid.8
+
+logsave.8: $(DEP_SUBSTITUTE) $(srcdir)/logsave.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/logsave.8.in logsave.8
+
+uuidd.8: $(DEP_SUBSTITUTE) $(srcdir)/uuidd.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/uuidd.8.in uuidd.8
+
+chattr.1: $(DEP_SUBSTITUTE) $(srcdir)/chattr.1.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/chattr.1.in chattr.1
+
+lsattr.1: $(DEP_SUBSTITUTE) $(srcdir)/lsattr.1.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/lsattr.1.in lsattr.1
+
+uuidgen.1: $(DEP_SUBSTITUTE) $(srcdir)/uuidgen.1.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/uuidgen.1.in uuidgen.1
+
+blkid.1: $(DEP_SUBSTITUTE) $(srcdir)/blkid.1.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/blkid.1.in blkid.1
+
+e2freefrag.8: $(DEP_SUBSTITUTE) $(srcdir)/e2freefrag.8.in
+ $(E) " SUBST $@"
+ @$(SUBSTITUTE_UPTIME) $(srcdir)/e2freefrag.8.in e2freefrag.8
+
+filefrag.8: $(DEP_SUBSTITUTE) $(srcdir)/filefrag.8.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/filefrag.8.in filefrag.8
+
+installdirs:
+ $(E) " MKINSTALLDIRS $(sbindir) $(root_sbindir) $(bindir) $(man1dir) $(man8dir) $(libdir) $(root_sysconfdir)"
+ $(Q) $(MKINSTALLDIRS) $(DESTDIR)$(sbindir) \
+ $(DESTDIR)$(root_sbindir) $(DESTDIR)$(bindir) \
+ $(DESTDIR)$(man1dir) $(DESTDIR)$(man8dir) \
+ $(DESTDIR)$(man1dir) $(DESTDIR)$(man5dir) \
+ $(DESTDIR)$(libdir) $(DESTDIR)/$(root_sysconfdir)
+
+install: all $(SMANPAGES) $(UMANPAGES) installdirs
+ $(Q) for i in $(SPROGS); do \
+ $(ES) " INSTALL $(root_sbindir)/$$i"; \
+ $(INSTALL_PROGRAM) $$i $(DESTDIR)$(root_sbindir)/$$i; \
+ done
+ $(Q) for i in $(USPROGS); do \
+ $(ES) " INSTALL $(sbindir)/$$i"; \
+ $(INSTALL_PROGRAM) $$i $(DESTDIR)$(sbindir)/$$i; \
+ done
+ $(Q) for i in ext2 ext3 ext4 ext4dev; do \
+ $(ES) " LINK $(root_sbindir)/mkfs.$$i"; \
+ (cd $(DESTDIR)$(root_sbindir); \
+ $(LN) $(LINK_INSTALL_FLAGS) mke2fs mkfs.$$i); \
+ done
+ $(Q) (cd $(DESTDIR)$(root_sbindir); \
+ $(LN) $(LINK_INSTALL_FLAGS) tune2fs e2label)
+ $(Q) if test -n "$(FINDFS_LINK)"; then \
+ $(ES) " LINK $(root_sbindir)/findfs"; \
+ (cd $(DESTDIR)$(root_sbindir); \
+ $(LN) $(LINK_INSTALL_FLAGS) tune2fs $(FINDFS_LINK)); \
+ fi
+ $(Q) for i in $(UPROGS); do \
+ $(ES) " INSTALL $(bindir)/$$i"; \
+ $(INSTALL_PROGRAM) $$i $(DESTDIR)$(bindir)/$$i; \
+ done
+ $(Q) for i in $(LPROGS); do \
+ $(ES) " INSTALL $(libdir)/$$i"; \
+ $(INSTALL_PROGRAM) $$i $(DESTDIR)$(libdir)/$$i; \
+ done
+ $(Q) for i in $(SMANPAGES); do \
+ for j in $(COMPRESS_EXT); do \
+ $(RM) -f $(DESTDIR)$(man8dir)/$$i.$$j; \
+ done; \
+ $(ES) " INSTALL_DATA $(man8dir)/$$i"; \
+ $(INSTALL_DATA) $$i $(DESTDIR)$(man8dir)/$$i; \
+ done
+ $(Q) $(RM) -f $(DESTDIR)$(man8dir)/mkfs.ext2.8.gz \
+ $(DESTDIR)$(man8dir)/mkfs.ext3.8.gz
+ $(Q) for i in ext2 ext3 ext4 ext4dev; do \
+ $(ES) " LINK mkfs.$$i.8"; \
+ (cd $(DESTDIR)$(man8dir); \
+ $(LN) $(LINK_INSTALL_FLAGS) mke2fs.8 mkfs.$$i.8); \
+ done
+ $(Q) for i in $(UMANPAGES); do \
+ for j in $(COMPRESS_EXT); do \
+ $(RM) -f $(DESTDIR)$(man1dir)/$$i.$$j; \
+ done; \
+ $(ES) " INSTALL_DATA $(man1dir)/$$i"; \
+ $(INSTALL_DATA) $$i $(DESTDIR)$(man1dir)/$$i; \
+ done
+ $(Q) for i in $(FMANPAGES); do \
+ for j in $(COMPRESS_EXT); do \
+ $(RM) -f $(DESTDIR)$(man5dir)/$$i.$$j; \
+ done; \
+ $(ES) " INSTALL_DATA $(man5dir)/$$i"; \
+ $(INSTALL_DATA) $$i $(DESTDIR)$(man5dir)/$$i; \
+ done
+ $(Q) for i in ext2 ext3; do \
+ $(ES) " LINK $$i.5"; \
+ (cd $(DESTDIR)$(man5dir); \
+ $(LN) $(LINK_INSTALL_FLAGS) ext4.5 $$i.5); \
+ done
+ $(Q) if test -f $(DESTDIR)$(root_sysconfdir)/mke2fs.conf; then \
+ if cmp -s $(DESTDIR)$(root_sysconfdir)/mke2fs.conf \
+ mke2fs.conf; then \
+ true; \
+ else \
+ if grep -q ext4dev $(DESTDIR)$(root_sysconfdir)/mke2fs.conf ; then \
+ $(ES) " INSTALL_DATA $(root_sysconfdir)/mke2fs.conf.e2fsprogs-new"; \
+ $(INSTALL_DATA) mke2fs.conf \
+ $(DESTDIR)$(root_sysconfdir)/mke2fs.conf.e2fsprogs-new; \
+ echo "Warning: installing mke2fs.conf in $(DESTDIR)$(root_sysconfdir)/mke2fs.conf.e2fsprogs-new"; \
+ echo "Check to see if you need to update your $(root_sysconfdir)/mke2fs.conf"; \
+ else \
+ $(ES) " INSTALL_DATA $(root_sysconfdir)/mke2fs.conf"; \
+ mv $(DESTDIR)$(root_sysconfdir)/mke2fs.conf \
+ $(DESTDIR)$(root_sysconfdir)/mke2fs.conf.e2fsprogs-old; \
+ $(INSTALL_DATA) mke2fs.conf \
+ $(DESTDIR)$(root_sysconfdir)/mke2fs.conf; \
+ echo "Your mke2fs.conf is too old. Backing up old version in"; \
+ echo "$(DESTDIR)$(root_sysconfdir)/mke2fs.conf.e2fsprogs-old. Please check to see"; \
+ echo "if you have any local customizations that you wish to preserve."; \
+ fi; \
+ echo " "; \
+ fi; \
+ else \
+ $(ES) " INSTALL_DATA $(root_sysconfdir)/mke2fs.conf"; \
+ $(INSTALL_DATA) mke2fs.conf \
+ $(DESTDIR)$(root_sysconfdir)/mke2fs.conf; \
+ fi
+
+install-strip: install
+ $(Q) for i in $(SPROGS); do \
+ $(E) " STRIP $(root_sbindir)/$$i"; \
+ $(STRIP) $(DESTDIR)$(root_sbindir)/$$i; \
+ done
+ $(Q) for i in $(USPROGS); do \
+ $(E) " STRIP $(sbindir)/$$i"; \
+ $(STRIP) $(DESTDIR)$(sbindir)/$$i; \
+ done
+
+uninstall:
+ for i in $(SPROGS); do \
+ $(RM) -f $(DESTDIR)$(root_sbindir)/$$i; \
+ done
+ for i in $(USPROGS); do \
+ $(RM) -f $(DESTDIR)$(sbindir)/$$i; \
+ done
+ for i in $(LPROGS); do \
+ $(RM) -f $(DESTDIR)$(libdir)/$$i; \
+ done
+ $(RM) -f $(DESTDIR)$(root_sbindir)/mkfs.ext2 \
+ $(DESTDIR)$(root_sbindir)/mkfs.ext3 \
+ $(DESTDIR)$(root_sbindir)/mkfs.ext4 \
+ $(DESTDIR)$(root_sbindir)/mkfs.ext4dev
+ for i in $(UPROGS); do \
+ $(RM) -f $(DESTDIR)$(bindir)/$$i; \
+ done
+ for i in $(SMANPAGES); do \
+ $(RM) -f $(DESTDIR)$(man8dir)/$$i; \
+ done
+ $(RM) -f $(DESTDIR)$(man8dir)/mkfs.ext2.8 \
+ $(DESTDIR)$(man8dir)/mkfs.ext3.8 \
+ $(DESTDIR)$(man8dir)/mkfs.ext4.8 \
+ $(DESTDIR)$(man8dir)/mkfs.ext4dev.8 \
+ $(DESTDIR)$(man8dir)/fsck.ext2.8 \
+ $(DESTDIR)$(man8dir)/fsck.ext3.8 \
+ $(DESTDIR)$(man8dir)/fsck.ext4.8 \
+ $(DESTDIR)$(man8dir)/fsck.ext4dev.8
+
+ for i in $(UMANPAGES); do \
+ $(RM) -f $(DESTDIR)$(man1dir)/$$i; \
+ done
+ for i in $(FINDFS_LINK) e2label ; do \
+ $(RM) -f $(DESTDIR)$(root_sbindir)/$$i; \
+ done
+ for i in $(FMANPAGES); do \
+ $(RM) -f $(DESTDIR)$(man5dir)/$$i; \
+ done
+ $(Q) for i in ext2 ext3; do \
+ $(ES) " LINK $$i.5"; \
+ $(RM) -f $(DESTDIR)$(man5dir)/$$i.5; \
+ done
+ if cmp -s mke2fs.conf $(DESTDIR)/$(root_sysconfdir)/mke2fs.conf; then \
+ $(RM) $(DESTDIR)/$(root_sysconfdir)/mke2fs.conf; \
+ fi
+
+clean:
+ $(RM) -f $(SPROGS) $(USPROGS) $(UPROGS) $(UMANPAGES) $(SMANPAGES) \
+ $(FMANPAGES) profile.h \
+ base_device base_device.out mke2fs.static filefrag e2freefrag \
+ e2initrd_helper partinfo prof_err.[ch] default_profile.c \
+ uuidd e2image tune2fs.static tst_ismounted fsck.profiled \
+ blkid.profiled tune2fs.profiled e2image.profiled \
+ e2undo.profiled mke2fs.profiled dumpe2fs.profiled \
+ logsave.profiled filefrag.profiled uuidgen.profiled \
+ uuidd.profiled e2image.profiled mke2fs.conf \
+ profiled/*.o \#* *.s *.o *.a *~ core gmon.out
+
+mostlyclean: clean
+distclean: clean
+ $(RM) -f .depend Makefile $(srcdir)/TAGS $(srcdir)/Makefile.in.old
+
+# +++ Dependency line eater +++
+#
+# Makefile dependencies follow. This must be the last section in
+# the Makefile.in file
+#
+tune2fs.o: $(srcdir)/tune2fs.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.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 \
+ $(top_srcdir)/lib/e2p/e2p.h $(srcdir)/jfs_user.h \
+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
+ $(top_srcdir)/lib/ext2fs/kernel-list.h $(srcdir)/util.h \
+ $(top_srcdir)/lib/quota/mkquota.h $(top_srcdir)/lib/quota/quotaio.h \
+ $(top_srcdir)/lib/quota/dqblk_v2.h $(top_srcdir)/lib/quota/quotaio_tree.h \
+ $(top_srcdir)/lib/../e2fsck/dict.h $(top_srcdir)/version.h \
+ $(srcdir)/nls-enable.h
+mklost+found.o: $(srcdir)/mklost+found.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/version.h \
+ $(srcdir)/nls-enable.h
+mke2fs.o: $(srcdir)/mke2fs.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fsP.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 \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(srcdir)/util.h profile.h prof_err.h $(top_srcdir)/version.h \
+ $(srcdir)/nls-enable.h $(top_srcdir)/lib/quota/mkquota.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+chattr.o: $(srcdir)/chattr.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/version.h $(srcdir)/nls-enable.h
+lsattr.o: $(srcdir)/lsattr.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/version.h $(srcdir)/nls-enable.h
+dumpe2fs.o: $(srcdir)/dumpe2fs.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.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 \
+ $(top_srcdir)/lib/e2p/e2p.h $(srcdir)/jfs_user.h \
+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
+ $(top_srcdir)/lib/ext2fs/kernel-list.h $(top_srcdir)/version.h \
+ $(srcdir)/nls-enable.h
+badblocks.o: $(srcdir)/badblocks.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.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_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(srcdir)/nls-enable.h
+fsck.o: $(srcdir)/fsck.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/version.h \
+ $(srcdir)/nls-enable.h $(srcdir)/fsck.h
+util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/e2p/e2p.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)/nls-enable.h $(srcdir)/util.h
+uuidgen.o: $(srcdir)/uuidgen.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/nls-enable.h
+blkid.o: $(srcdir)/blkid.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.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
+logsave.o: $(srcdir)/logsave.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h
+filefrag.o: $(srcdir)/filefrag.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.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 \
+ $(top_srcdir)/lib/ext2fs/fiemap.h
+base_device.o: $(srcdir)/base_device.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/fsck.h
+ismounted.o: $(srcdir)/ismounted.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/fsck.h \
+ $(top_srcdir)/lib/et/com_err.h
+profile.o: $(srcdir)/../e2fsck/profile.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/../e2fsck/profile.h prof_err.h
+e2undo.o: $(srcdir)/e2undo.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/tdb.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.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)/nls-enable.h
+e2freefrag.o: $(srcdir)/e2freefrag.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.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)/e2freefrag.h
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/badblocks.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/badblocks.8.in
new file mode 100644
index 0000000..f507f63
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/badblocks.8.in
@@ -0,0 +1,234 @@
+.\" -*- nroff -*-
+.TH BADBLOCKS 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+badblocks \- search a device for bad blocks
+.SH SYNOPSIS
+.B badblocks
+[
+.B \-svwnfBX
+]
+[
+.B \-b
+.I block-size
+]
+[
+.B \-c
+.I blocks_at_once
+]
+[
+.B \-e
+.I max_bad_blocks
+]
+[
+.B \-d
+.I read_delay_factor
+]
+[
+.B \-i
+.I input_file
+]
+[
+.B \-o
+.I output_file
+]
+[
+.B \-p
+.I num_passes
+]
+[
+.B \-t
+.I test_pattern
+]
+.I device
+[
+.I last-block
+] [
+.I first-block
+]
+.SH DESCRIPTION
+.B badblocks
+is used to search for bad blocks on a device (usually a disk partition).
+.I device
+is the special file corresponding to the device (e.g
+.IR /dev/hdc1 ).
+.I last-block
+is the last block to be checked; if it is not specified, the last block
+on the device is used as a default.
+.I first-block
+is an optional parameter specifying the starting block number
+for the test, which allows the testing to start in the middle of the
+disk. If it is not specified the first block on the disk is used as a default.
+.PP
+.B Important note:
+If the output of
+.B badblocks
+is going to be fed to the
+.B e2fsck
+or
+.B mke2fs
+programs, it is important that the block size is properly specified,
+since the block numbers which are generated are very dependent on the
+block size in use by the filesystem.
+For this reason, it is strongly recommended that
+users
+.B not
+run
+.B badblocks
+directly, but rather use the
+.B \-c
+option of the
+.B e2fsck
+and
+.B mke2fs
+programs.
+.SH OPTIONS
+.TP
+.BI \-b " block-size"
+Specify the size of blocks in bytes. The default is 1024.
+.TP
+.BI \-c " number of blocks"
+is the number of blocks which are tested at a time. The default is 64.
+.TP
+.BI \-e " max bad block count"
+Specify a maximum number of bad blocks before aborting the test. The
+default is 0, meaning the test will continue until the end of the test
+range is reached.
+.TP
+.BI \-d " read delay factor"
+This parameter, if passed and non-zero, will cause bad blocks to sleep
+between reads if there were no errors encountered in the read
+operation; the delay will be calculated as a percentage of the time it
+took for the read operation to be performed. In other words, a value of
+100 will cause each read to be delayed by the amount the previous read
+took, and a value of 200 by twice the amount.
+.TP
+.B \-f
+Normally, badblocks will refuse to do a read/write or a non-destructive
+test on a device which is mounted, since either can cause the system to
+potentially crash and/or damage the filesystem even if it is mounted
+read-only. This can be overridden using the
+.B \-f
+flag, but should almost never be used --- if you think you're smarter
+than the
+.B badblocks
+program, you almost certainly aren't. The only time when this option
+might be safe to use is if the /etc/mtab file is incorrect, and the device
+really isn't mounted.
+.TP
+.BI \-i " input_file"
+Read a list of already existing known bad blocks.
+.B Badblocks
+will skip testing these blocks since they are known to be bad. If
+.I input_file
+is specified as "-", the list will be read from the standard input.
+Blocks listed in this list will be omitted from the list of
+.I new
+bad blocks produced on the standard output or in the output file.
+The
+.B \-b
+option of
+.BR dumpe2fs (8)
+can be used to retrieve the list of blocks currently marked bad on
+an existing filesystem, in a format suitable for use with this option.
+.TP
+.B \-n
+Use non-destructive read-write mode. By default only a non-destructive
+read-only test is done. This option must not be combined with the
+.B \-w
+option, as they are mutually exclusive.
+.TP
+.BI \-o " output_file"
+Write the list of bad blocks to the specified file. Without this option,
+.B badblocks
+displays the list on its standard output. The format of this file is suitable
+for use by the
+.
+.B \-l
+option in
+.BR e2fsck (8)
+or
+.BR mke2fs (8).
+.TP
+.BI \-p " num_passes"
+Repeat scanning the disk until there are no new blocks discovered in
+num_passes consecutive scans of the disk.
+Default is 0, meaning
+.B badblocks
+will exit after the first pass.
+.TP
+.B \-s
+Show the progress of the scan by writing out rough percentage completion
+of the current badblocks pass over the disk. Note that badblocks may do
+multiple test passes over the disk, in particular if the
+.B \-p
+or
+.B \-w
+option is requested by the user.
+.TP
+.BI \-t " test_pattern"
+Specify a test pattern to be read (and written) to disk blocks. The
+.I test_pattern
+may either be a numeric value between 0 and ULONG_MAX-1 inclusive, or the word
+"random", which specifies that the block should be filled with a random
+bit pattern.
+For read/write (\fB-w\fR) and non-destructive (\fB-n\fR) modes,
+one or more test patterns may be specified by specifying the
+.B -t
+option for each test pattern desired. For
+read-only mode only a single pattern may be specified and it may not be
+"random". Read-only testing with a pattern assumes that the
+specified pattern has previously been written to the disk - if not, large
+numbers of blocks will fail verification.
+If multiple patterns
+are specified then all blocks will be tested with one pattern
+before proceeding to the next pattern.
+.TP
+.B \-v
+Verbose mode. Will write the number of read errors, write errors and data-
+corruptions to stderr.
+.TP
+.B \-w
+Use write-mode test. With this option,
+.B badblocks
+scans for bad blocks by writing some patterns (0xaa, 0x55, 0xff, 0x00) on
+every block of the device, reading every block and comparing the contents.
+This option may not be combined with the
+.B \-n
+option, as they are mutually exclusive.
+.TP
+.B \-B
+Use buffered I/O and do not use Direct I/O, even if it is available.
+.TP
+.B \-X
+Internal flag only to be used by
+.BR e2fsck (8)
+and
+.BR mke2fs (8).
+It bypasses the exclusive mode in-use device safety check.
+.SH WARNING
+Never use the
+.B \-w
+option on a device containing an existing file system.
+This option erases data! If you want to do write-mode testing on
+an existing file system, use the
+.B \-n
+option instead. It is slower, but it will preserve your data.
+.PP
+The
+.B \-e
+option will cause badblocks to output a possibly incomplete list of
+bad blocks. Therefore it is recommended to use it only when one wants
+to know if there are any bad blocks at all on the device, and not when
+the list of bad blocks is wanted.
+.SH AUTHOR
+.B badblocks
+was written by Remy Card <Remy.Card@linux.org>. Current maintainer is
+Theodore Ts'o <tytso@alum.mit.edu>. Non-destructive read/write test
+implemented by David Beattie <dbeattie@softhome.net>.
+.SH AVAILABILITY
+.B badblocks
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR e2fsck (8),
+.BR mke2fs (8)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/badblocks.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/badblocks.c
new file mode 100644
index 0000000..912ef28
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/badblocks.c
@@ -0,0 +1,1332 @@
+/*
+ * badblocks.c - Bad blocks checker
+ *
+ * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o
+ * Copyright 1999 by David Beattie
+ *
+ * This file is based on the minix file system programs fsck and mkfs
+ * written and copyrighted by Linus Torvalds <Linus.Torvalds@cs.helsinki.fi>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/*
+ * History:
+ * 93/05/26 - Creation from e2fsck
+ * 94/02/27 - Made a separate bad blocks checker
+ * 99/06/30...99/07/26 - Added non-destructive write-testing,
+ * configurable blocks-at-once parameter,
+ * loading of badblocks list to avoid testing
+ * blocks known to be bad, multiple passes to
+ * make sure that no new blocks are added to the
+ * list. (Work done by David Beattie)
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* for O_DIRECT */
+#endif
+
+#include "config.h"
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <setjmp.h>
+#include <time.h>
+#include <limits.h>
+
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include "et/com_err.h"
+#include "ext2fs/ext2_io.h"
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+#include "nls-enable.h"
+
+#ifndef O_LARGEFILE
+#define O_LARGEFILE 0
+#endif
+
+static const char * program_name = "badblocks";
+static const char * done_string = N_("done \n");
+
+static int v_flag; /* verbose */
+static int w_flag; /* do r/w test: 0=no, 1=yes,
+ * 2=non-destructive */
+static int s_flag; /* show progress of test */
+static int force; /* force check of mounted device */
+static int t_flag; /* number of test patterns */
+static int t_max; /* allocated test patterns */
+static unsigned int *t_patts; /* test patterns */
+static int use_buffered_io;
+static int exclusive_ok;
+static unsigned int max_bb; /* Abort test if more than this number of bad blocks has been encountered */
+static unsigned int d_flag; /* delay factor between reads */
+static struct timeval time_start;
+
+#define T_INC 32
+
+static unsigned int sys_page_size = 4096;
+
+static void usage(void)
+{
+ fprintf(stderr, _(
+"Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnf]\n"
+" [-c blocks_at_once] [-d delay_factor_between_reads] [-e max_bad_blocks]\n"
+" [-p num_passes] [-t test_pattern [-t test_pattern [...]]]\n"
+" device [last_block [first_block]]\n"),
+ program_name);
+ exit (1);
+}
+
+static void exclusive_usage(void)
+{
+ fprintf(stderr,
+ _("%s: The -n and -w options are mutually exclusive.\n\n"),
+ program_name);
+ exit(1);
+}
+
+static blk_t currently_testing = 0;
+static blk_t num_blocks = 0;
+static blk_t num_read_errors = 0;
+static blk_t num_write_errors = 0;
+static blk_t num_corruption_errors = 0;
+static ext2_badblocks_list bb_list = NULL;
+static FILE *out;
+static blk_t next_bad = 0;
+static ext2_badblocks_iterate bb_iter = NULL;
+
+enum error_types { READ_ERROR, WRITE_ERROR, CORRUPTION_ERROR };
+
+static void *allocate_buffer(size_t size)
+{
+ void *ret = 0;
+
+#ifdef HAVE_POSIX_MEMALIGN
+ if (posix_memalign(&ret, sys_page_size, size) < 0)
+ ret = 0;
+#else
+#ifdef HAVE_MEMALIGN
+ ret = memalign(sys_page_size, size);
+#else
+#ifdef HAVE_VALLOC
+ ret = valloc(size);
+#endif /* HAVE_VALLOC */
+#endif /* HAVE_MEMALIGN */
+#endif /* HAVE_POSIX_MEMALIGN */
+
+ if (!ret)
+ ret = malloc(size);
+
+ return ret;
+}
+
+/*
+ * This routine reports a new bad block. If the bad block has already
+ * been seen before, then it returns 0; otherwise it returns 1.
+ */
+static int bb_output (blk_t bad, enum error_types error_type)
+{
+ errcode_t errcode;
+
+ if (ext2fs_badblocks_list_test(bb_list, bad))
+ return 0;
+
+ fprintf(out, "%lu\n", (unsigned long) bad);
+ fflush(out);
+
+ errcode = ext2fs_badblocks_list_add (bb_list, bad);
+ if (errcode) {
+ com_err (program_name, errcode, "adding to in-memory bad block list");
+ exit (1);
+ }
+
+ /* kludge:
+ increment the iteration through the bb_list if
+ an element was just added before the current iteration
+ position. This should not cause next_bad to change. */
+ if (bb_iter && bad < next_bad)
+ ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+
+ if (error_type == READ_ERROR) {
+ num_read_errors++;
+ } else if (error_type == WRITE_ERROR) {
+ num_write_errors++;
+ } else if (error_type == CORRUPTION_ERROR) {
+ num_corruption_errors++;
+ }
+ return 1;
+}
+
+static char *time_diff_format(struct timeval *tv1,
+ struct timeval *tv2, char *buf)
+{
+ time_t diff = (tv1->tv_sec - tv2->tv_sec);
+ int hr,min,sec;
+
+ sec = diff % 60;
+ diff /= 60;
+ min = diff % 60;
+ hr = diff / 60;
+
+ if (hr)
+ sprintf(buf, "%d:%02d:%02d", hr, min, sec);
+ else
+ sprintf(buf, "%d:%02d", min, sec);
+ return buf;
+}
+
+static float calc_percent(unsigned long current, unsigned long total) {
+ float percent = 0.0;
+ if (total <= 0)
+ return percent;
+ if (current >= total) {
+ percent = 100.0;
+ } else {
+ percent=(100.0*(float)current/(float)total);
+ }
+ return percent;
+}
+
+static void print_status(void)
+{
+ struct timeval time_end;
+ char diff_buf[32], line_buf[128];
+ int len;
+
+ gettimeofday(&time_end, 0);
+ len = snprintf(line_buf, sizeof(line_buf),
+ _("%6.2f%% done, %s elapsed. "
+ "(%d/%d/%d errors)"),
+ calc_percent((unsigned long) currently_testing,
+ (unsigned long) num_blocks),
+ time_diff_format(&time_end, &time_start, diff_buf),
+ num_read_errors,
+ num_write_errors,
+ num_corruption_errors);
+#ifdef HAVE_MBSTOWCS
+ len = mbstowcs(NULL, line_buf, sizeof(line_buf));
+#endif
+ fputs(line_buf, stderr);
+ memset(line_buf, '\b', len);
+ line_buf[len] = 0;
+ fputs(line_buf, stderr);
+ fflush (stderr);
+}
+
+static void alarm_intr(int alnum EXT2FS_ATTR((unused)))
+{
+ signal (SIGALRM, alarm_intr);
+ alarm(1);
+ if (!num_blocks)
+ return;
+ print_status();
+}
+
+static void *terminate_addr = NULL;
+
+static void terminate_intr(int signo EXT2FS_ATTR((unused)))
+{
+ fflush(out);
+ fprintf(stderr, "\n\nInterrupted at block %llu\n",
+ (unsigned long long) currently_testing);
+ fflush(stderr);
+ if (terminate_addr)
+ longjmp(terminate_addr,1);
+ exit(1);
+}
+
+static void capture_terminate(jmp_buf term_addr)
+{
+ terminate_addr = term_addr;
+ signal (SIGHUP, terminate_intr);
+ signal (SIGINT, terminate_intr);
+ signal (SIGPIPE, terminate_intr);
+ signal (SIGTERM, terminate_intr);
+ signal (SIGUSR1, terminate_intr);
+ signal (SIGUSR2, terminate_intr);
+}
+
+static void uncapture_terminate(void)
+{
+ terminate_addr = NULL;
+ signal (SIGHUP, SIG_DFL);
+ signal (SIGINT, SIG_DFL);
+ signal (SIGPIPE, SIG_DFL);
+ signal (SIGTERM, SIG_DFL);
+ signal (SIGUSR1, SIG_DFL);
+ signal (SIGUSR2, SIG_DFL);
+}
+
+/* Linux requires that O_DIRECT I/Os be 512-byte sector aligned */
+
+#define O_DIRECT_SIZE 512
+
+static void set_o_direct(int dev, unsigned char *buffer, size_t size,
+ ext2_loff_t offset)
+{
+#ifdef O_DIRECT
+ static int current_O_DIRECT; /* Current status of O_DIRECT flag */
+ int new_flag = O_DIRECT;
+ int flag;
+
+ if ((use_buffered_io != 0) ||
+ (((unsigned long) buffer & (sys_page_size - 1)) != 0) ||
+ ((size & (sys_page_size - 1)) != 0) ||
+ ((offset & (O_DIRECT_SIZE - 1)) != 0))
+ new_flag = 0;
+
+ if (new_flag != current_O_DIRECT) {
+ /* printf("%s O_DIRECT\n", new_flag ? "Setting" : "Clearing"); */
+ flag = fcntl(dev, F_GETFL);
+ if (flag > 0) {
+ flag = (flag & ~O_DIRECT) | new_flag;
+ fcntl(dev, F_SETFL, flag);
+ }
+ current_O_DIRECT = new_flag;
+ }
+#endif
+}
+
+
+static void pattern_fill(unsigned char *buffer, unsigned int pattern,
+ size_t n)
+{
+ unsigned int i, nb;
+ unsigned char bpattern[sizeof(pattern)], *ptr;
+
+ if (pattern == (unsigned int) ~0) {
+ for (ptr = buffer; ptr < buffer + n; ptr++) {
+ (*ptr) = random() % (1 << (8 * sizeof(char)));
+ }
+ if (s_flag | v_flag)
+ fputs(_("Testing with random pattern: "), stderr);
+ } else {
+ bpattern[0] = 0;
+ for (i = 0; i < sizeof(bpattern); i++) {
+ if (pattern == 0)
+ break;
+ bpattern[i] = pattern & 0xFF;
+ pattern = pattern >> 8;
+ }
+ nb = i ? (i-1) : 0;
+ for (ptr = buffer, i = nb; ptr < buffer + n; ptr++) {
+ *ptr = bpattern[i];
+ if (i == 0)
+ i = nb;
+ else
+ i--;
+ }
+ if (s_flag | v_flag) {
+ fputs(_("Testing with pattern 0x"), stderr);
+ for (i = 0; i <= nb; i++)
+ fprintf(stderr, "%02x", buffer[i]);
+ fputs(": ", stderr);
+ }
+ }
+}
+
+/*
+ * Perform a read of a sequence of blocks; return the number of blocks
+ * successfully sequentially read.
+ */
+static int do_read (int dev, unsigned char * buffer, int try, int block_size,
+ blk_t current_block)
+{
+ long got;
+ struct timeval tv1, tv2;
+#define NANOSEC (1000000000L)
+#define MILISEC (1000L)
+
+#if 0
+ printf("do_read: block %d, try %d\n", current_block, try);
+#endif
+ set_o_direct(dev, buffer, try * block_size,
+ ((ext2_loff_t) current_block) * block_size);
+
+ if (v_flag > 1)
+ print_status();
+
+ /* Seek to the correct loc. */
+ if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
+ SEEK_SET) != (ext2_loff_t) current_block * block_size)
+ com_err (program_name, errno, "%s", _("during seek"));
+
+ /* Try the read */
+ if (d_flag)
+ gettimeofday(&tv1, NULL);
+ got = read (dev, buffer, try * block_size);
+ if (d_flag)
+ gettimeofday(&tv2, NULL);
+ if (got < 0)
+ got = 0;
+ if (got & 511)
+ fprintf(stderr, _("Weird value (%ld) in do_read\n"), got);
+ got /= block_size;
+ if (d_flag && got == try) {
+#ifdef HAVE_NANOSLEEP
+ struct timespec ts;
+ ts.tv_sec = tv2.tv_sec - tv1.tv_sec;
+ ts.tv_nsec = (tv2.tv_usec - tv1.tv_usec) * MILISEC;
+ if (ts.tv_nsec < 0) {
+ ts.tv_nsec += NANOSEC;
+ ts.tv_sec -= 1;
+ }
+ /* increase/decrease the sleep time based on d_flag value */
+ ts.tv_sec = ts.tv_sec * d_flag / 100;
+ ts.tv_nsec = ts.tv_nsec * d_flag / 100;
+ if (ts.tv_nsec > NANOSEC) {
+ ts.tv_sec += ts.tv_nsec / NANOSEC;
+ ts.tv_nsec %= NANOSEC;
+ }
+ if (ts.tv_sec || ts.tv_nsec)
+ nanosleep(&ts, NULL);
+#else
+#ifdef HAVE_USLEEP
+ struct timeval tv;
+ tv.tv_sec = tv2.tv_sec - tv1.tv_sec;
+ tv.tv_usec = tv2.tv_usec - tv1.tv_usec;
+ tv.tv_sec = tv.tv_sec * d_flag / 100;
+ tv.tv_usec = tv.tv_usec * d_flag / 100;
+ if (tv.tv_usec > 1000000) {
+ tv.tv_sec += tv.tv_usec / 1000000;
+ tv.tv_usec %= 1000000;
+ }
+ if (tv.tv_sec)
+ sleep(tv.tv_sec);
+ if (tv.tv_usec)
+ usleep(tv.tv_usec);
+#endif
+#endif
+ }
+ return got;
+}
+
+/*
+ * Perform a write of a sequence of blocks; return the number of blocks
+ * successfully sequentially written.
+ */
+static int do_write(int dev, unsigned char * buffer, int try, int block_size,
+ unsigned long current_block)
+{
+ long got;
+
+#if 0
+ printf("do_write: block %lu, try %d\n", current_block, try);
+#endif
+ set_o_direct(dev, buffer, try * block_size,
+ ((ext2_loff_t) current_block) * block_size);
+
+ if (v_flag > 1)
+ print_status();
+
+ /* Seek to the correct loc. */
+ if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
+ SEEK_SET) != (ext2_loff_t) current_block * block_size)
+ com_err (program_name, errno, "%s", _("during seek"));
+
+ /* Try the write */
+ got = write (dev, buffer, try * block_size);
+ if (got < 0)
+ got = 0;
+ if (got & 511)
+ fprintf(stderr, "Weird value (%ld) in do_write\n", got);
+ got /= block_size;
+ return got;
+}
+
+static int host_dev;
+
+static void flush_bufs(void)
+{
+ errcode_t retval;
+
+#ifdef O_DIRECT
+ if (!use_buffered_io)
+ return;
+#endif
+ retval = ext2fs_sync_device(host_dev, 1);
+ if (retval)
+ com_err(program_name, retval, "%s",
+ _("during ext2fs_sync_device"));
+}
+
+static unsigned int test_ro (int dev, blk_t last_block,
+ int block_size, blk_t first_block,
+ unsigned int blocks_at_once)
+{
+ unsigned char * blkbuf;
+ int try;
+ int got;
+ unsigned int bb_count = 0;
+ errcode_t errcode;
+ blk_t recover_block = ~0;
+
+ /* set up abend handler */
+ capture_terminate(NULL);
+
+ errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
+ if (errcode) {
+ com_err(program_name, errcode, "%s",
+ _("while beginning bad block list iteration"));
+ exit (1);
+ }
+ do {
+ ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+ } while (next_bad && next_bad < first_block);
+
+ if (t_flag) {
+ blkbuf = allocate_buffer((blocks_at_once + 1) * block_size);
+ } else {
+ blkbuf = allocate_buffer(blocks_at_once * block_size);
+ }
+ if (!blkbuf)
+ {
+ com_err(program_name, ENOMEM, "%s",
+ _("while allocating buffers"));
+ exit (1);
+ }
+ if (v_flag) {
+ fprintf(stderr, _("Checking blocks %lu to %lu\n"),
+ (unsigned long)first_block,
+ (unsigned long)last_block - 1);
+ }
+ if (t_flag) {
+ fputs(_("Checking for bad blocks in read-only mode\n"), stderr);
+ pattern_fill(blkbuf + blocks_at_once * block_size,
+ t_patts[0], block_size);
+ }
+ flush_bufs();
+ try = blocks_at_once;
+ currently_testing = first_block;
+ num_blocks = last_block - 1;
+ if (!t_flag && (s_flag || v_flag))
+ fputs(_("Checking for bad blocks (read-only test): "), stderr);
+ if (s_flag && v_flag <= 1)
+ alarm_intr(SIGALRM);
+ while (currently_testing < last_block)
+ {
+ if (max_bb && bb_count >= max_bb) {
+ if (s_flag || v_flag) {
+ fputs(_("Too many bad blocks, aborting test\n"), stderr);
+ }
+ break;
+ }
+ if (next_bad) {
+ if (currently_testing == next_bad) {
+ /* fprintf (out, "%lu\n", nextbad); */
+ ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+ currently_testing++;
+ continue;
+ }
+ else if (currently_testing + try > next_bad)
+ try = next_bad - currently_testing;
+ }
+ if (currently_testing + try > last_block)
+ try = last_block - currently_testing;
+ got = do_read (dev, blkbuf, try, block_size, currently_testing);
+ if (t_flag) {
+ /* test the comparison between all the
+ blocks successfully read */
+ int i;
+ for (i = 0; i < got; ++i)
+ if (memcmp (blkbuf+i*block_size,
+ blkbuf+blocks_at_once*block_size,
+ block_size))
+ bb_count += bb_output(currently_testing + i, CORRUPTION_ERROR);
+ }
+ if (got == 0 && try == 1)
+ bb_count += bb_output(currently_testing++, READ_ERROR);
+ currently_testing += got;
+ if (got != try) {
+ try = 1;
+ if (recover_block == ~0U)
+ recover_block = currently_testing - got +
+ blocks_at_once;
+ continue;
+ } else if (currently_testing == recover_block) {
+ try = blocks_at_once;
+ recover_block = ~0;
+ }
+ }
+ num_blocks = 0;
+ alarm(0);
+ if (s_flag || v_flag)
+ fputs(_(done_string), stderr);
+
+ fflush (stderr);
+ free (blkbuf);
+
+ ext2fs_badblocks_list_iterate_end(bb_iter);
+
+ uncapture_terminate();
+
+ return bb_count;
+}
+
+static unsigned int test_rw (int dev, blk_t last_block,
+ int block_size, blk_t first_block,
+ unsigned int blocks_at_once)
+{
+ unsigned char *buffer, *read_buffer;
+ const unsigned int patterns[] = {0xaa, 0x55, 0xff, 0x00};
+ const unsigned int *pattern;
+ int i, try, got, nr_pattern, pat_idx;
+ unsigned int bb_count = 0;
+ blk_t recover_block = ~0;
+
+ /* set up abend handler */
+ capture_terminate(NULL);
+
+ buffer = allocate_buffer(2 * blocks_at_once * block_size);
+ read_buffer = buffer + blocks_at_once * block_size;
+
+ if (!buffer) {
+ com_err(program_name, ENOMEM, "%s",
+ _("while allocating buffers"));
+ exit (1);
+ }
+
+ flush_bufs();
+
+ if (v_flag) {
+ fputs(_("Checking for bad blocks in read-write mode\n"),
+ stderr);
+ fprintf(stderr, _("From block %lu to %lu\n"),
+ (unsigned long) first_block,
+ (unsigned long) last_block - 1);
+ }
+ if (t_flag) {
+ pattern = t_patts;
+ nr_pattern = t_flag;
+ } else {
+ pattern = patterns;
+ nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
+ }
+ for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
+ pattern_fill(buffer, pattern[pat_idx],
+ blocks_at_once * block_size);
+ num_blocks = last_block - 1;
+ currently_testing = first_block;
+ if (s_flag && v_flag <= 1)
+ alarm_intr(SIGALRM);
+
+ try = blocks_at_once;
+ while (currently_testing < last_block) {
+ if (max_bb && bb_count >= max_bb) {
+ if (s_flag || v_flag) {
+ fputs(_("Too many bad blocks, aborting test\n"), stderr);
+ }
+ break;
+ }
+ if (currently_testing + try > last_block)
+ try = last_block - currently_testing;
+ got = do_write(dev, buffer, try, block_size,
+ currently_testing);
+ if (v_flag > 1)
+ print_status();
+
+ if (got == 0 && try == 1)
+ bb_count += bb_output(currently_testing++, WRITE_ERROR);
+ currently_testing += got;
+ if (got != try) {
+ try = 1;
+ if (recover_block == ~0U)
+ recover_block = currently_testing -
+ got + blocks_at_once;
+ continue;
+ } else if (currently_testing == recover_block) {
+ try = blocks_at_once;
+ recover_block = ~0;
+ }
+ }
+
+ num_blocks = 0;
+ alarm (0);
+ if (s_flag | v_flag)
+ fputs(_(done_string), stderr);
+ flush_bufs();
+ if (s_flag | v_flag)
+ fputs(_("Reading and comparing: "), stderr);
+ num_blocks = last_block;
+ currently_testing = first_block;
+ if (s_flag && v_flag <= 1)
+ alarm_intr(SIGALRM);
+
+ try = blocks_at_once;
+ while (currently_testing < last_block) {
+ if (max_bb && bb_count >= max_bb) {
+ if (s_flag || v_flag) {
+ fputs(_("Too many bad blocks, aborting test\n"), stderr);
+ }
+ break;
+ }
+ if (currently_testing + try > last_block)
+ try = last_block - currently_testing;
+ got = do_read (dev, read_buffer, try, block_size,
+ currently_testing);
+ if (got == 0 && try == 1)
+ bb_count += bb_output(currently_testing++, READ_ERROR);
+ currently_testing += got;
+ if (got != try) {
+ try = 1;
+ if (recover_block == ~0U)
+ recover_block = currently_testing -
+ got + blocks_at_once;
+ continue;
+ } else if (currently_testing == recover_block) {
+ try = blocks_at_once;
+ recover_block = ~0U;
+ }
+ for (i=0; i < got; i++) {
+ if (memcmp(read_buffer + i * block_size,
+ buffer + i * block_size,
+ block_size))
+ bb_count += bb_output(currently_testing+i, CORRUPTION_ERROR);
+ }
+ if (v_flag > 1)
+ print_status();
+ }
+
+ num_blocks = 0;
+ alarm (0);
+ if (s_flag | v_flag)
+ fputs(_(done_string), stderr);
+ flush_bufs();
+ }
+ uncapture_terminate();
+ free(buffer);
+ return bb_count;
+}
+
+struct saved_blk_record {
+ blk_t block;
+ int num;
+};
+
+static unsigned int test_nd (int dev, blk_t last_block,
+ int block_size, blk_t first_block,
+ unsigned int blocks_at_once)
+{
+ unsigned char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
+ unsigned char *test_base, *save_base, *read_base;
+ int try, i;
+ const unsigned int patterns[] = { ~0 };
+ const unsigned int *pattern;
+ int nr_pattern, pat_idx;
+ int got, used2, written;
+ blk_t save_currently_testing;
+ struct saved_blk_record *test_record;
+ /* This is static to prevent being clobbered by the longjmp */
+ static int num_saved;
+ jmp_buf terminate_env;
+ errcode_t errcode;
+ unsigned long buf_used;
+ static unsigned int bb_count;
+ unsigned int granularity = blocks_at_once;
+ blk_t recover_block = ~0U;
+
+ bb_count = 0;
+ errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
+ if (errcode) {
+ com_err(program_name, errcode, "%s",
+ _("while beginning bad block list iteration"));
+ exit (1);
+ }
+ do {
+ ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+ } while (next_bad && next_bad < first_block);
+
+ blkbuf = allocate_buffer(3 * blocks_at_once * block_size);
+ test_record = malloc(blocks_at_once * sizeof(struct saved_blk_record));
+ if (!blkbuf || !test_record) {
+ com_err(program_name, ENOMEM, "%s",
+ _("while allocating buffers"));
+ exit (1);
+ }
+
+ save_base = blkbuf;
+ test_base = blkbuf + (blocks_at_once * block_size);
+ read_base = blkbuf + (2 * blocks_at_once * block_size);
+
+ num_saved = 0;
+
+ flush_bufs();
+ if (v_flag) {
+ fputs(_("Checking for bad blocks in non-destructive read-write mode\n"), stderr);
+ fprintf (stderr, _("From block %lu to %lu\n"),
+ (unsigned long) first_block,
+ (unsigned long) last_block - 1);
+ }
+ if (s_flag || v_flag > 1) {
+ fputs(_("Checking for bad blocks (non-destructive read-write test)\n"), stderr);
+ }
+ if (setjmp(terminate_env)) {
+ /*
+ * Abnormal termination by a signal is handled here.
+ */
+ signal (SIGALRM, SIG_IGN);
+ fputs(_("\nInterrupt caught, cleaning up\n"), stderr);
+
+ save_ptr = save_base;
+ for (i=0; i < num_saved; i++) {
+ do_write(dev, save_ptr, test_record[i].num,
+ block_size, test_record[i].block);
+ save_ptr += test_record[i].num * block_size;
+ }
+ fflush (out);
+ exit(1);
+ }
+
+ /* set up abend handler */
+ capture_terminate(terminate_env);
+
+ if (t_flag) {
+ pattern = t_patts;
+ nr_pattern = t_flag;
+ } else {
+ pattern = patterns;
+ nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
+ }
+ for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
+ pattern_fill(test_base, pattern[pat_idx],
+ blocks_at_once * block_size);
+
+ buf_used = 0;
+ bb_count = 0;
+ save_ptr = save_base;
+ test_ptr = test_base;
+ currently_testing = first_block;
+ num_blocks = last_block - 1;
+ if (s_flag && v_flag <= 1)
+ alarm_intr(SIGALRM);
+
+ while (currently_testing < last_block) {
+ if (max_bb && bb_count >= max_bb) {
+ if (s_flag || v_flag) {
+ fputs(_("Too many bad blocks, aborting test\n"), stderr);
+ }
+ break;
+ }
+ got = try = granularity - buf_used;
+ if (next_bad) {
+ if (currently_testing == next_bad) {
+ /* fprintf (out, "%lu\n", nextbad); */
+ ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+ currently_testing++;
+ goto check_for_more;
+ }
+ else if (currently_testing + try > next_bad)
+ try = next_bad - currently_testing;
+ }
+ if (currently_testing + try > last_block)
+ try = last_block - currently_testing;
+ got = do_read (dev, save_ptr, try, block_size,
+ currently_testing);
+ if (got == 0) {
+ if (recover_block == ~0U)
+ recover_block = currently_testing +
+ blocks_at_once;
+ if (granularity != 1) {
+ granularity = 1;
+ continue;
+ }
+ /* First block must have been bad. */
+ bb_count += bb_output(currently_testing++, READ_ERROR);
+ goto check_for_more;
+ }
+
+ /*
+ * Note the fact that we've saved this much data
+ * *before* we overwrite it with test data
+ */
+ test_record[num_saved].block = currently_testing;
+ test_record[num_saved].num = got;
+ num_saved++;
+
+ /* Write the test data */
+ written = do_write (dev, test_ptr, got, block_size,
+ currently_testing);
+ if (written != got)
+ com_err (program_name, errno,
+ _("during test data write, block %lu"),
+ (unsigned long) currently_testing +
+ written);
+
+ buf_used += got;
+ save_ptr += got * block_size;
+ test_ptr += got * block_size;
+ currently_testing += got;
+ if (got != try) {
+ try = 1;
+ if (recover_block == ~0U)
+ recover_block = currently_testing -
+ got + blocks_at_once;
+ continue;
+ }
+
+ check_for_more:
+ /*
+ * If there's room for more blocks to be tested this
+ * around, and we're not done yet testing the disk, go
+ * back and get some more blocks.
+ */
+ if ((buf_used != granularity) &&
+ (currently_testing < last_block))
+ continue;
+
+ if (currently_testing >= recover_block) {
+ granularity = blocks_at_once;
+ recover_block = ~0;
+ }
+
+ flush_bufs();
+ save_currently_testing = currently_testing;
+
+ /*
+ * for each contiguous block that we read into the
+ * buffer (and wrote test data into afterwards), read
+ * it back (looping if necessary, to get past newly
+ * discovered unreadable blocks, of which there should
+ * be none, but with a hard drive which is unreliable,
+ * it has happened), and compare with the test data
+ * that was written; output to the bad block list if
+ * it doesn't match.
+ */
+ used2 = 0;
+ save_ptr = save_base;
+ test_ptr = test_base;
+ read_ptr = read_base;
+ try = 0;
+
+ while (1) {
+ if (try == 0) {
+ if (used2 >= num_saved)
+ break;
+ currently_testing = test_record[used2].block;
+ try = test_record[used2].num;
+ used2++;
+ }
+
+ got = do_read (dev, read_ptr, try,
+ block_size, currently_testing);
+
+ /* test the comparison between all the
+ blocks successfully read */
+ for (i = 0; i < got; ++i)
+ if (memcmp (test_ptr+i*block_size,
+ read_ptr+i*block_size, block_size))
+ bb_count += bb_output(currently_testing + i, CORRUPTION_ERROR);
+ if (got < try) {
+ bb_count += bb_output(currently_testing + got, READ_ERROR);
+ got++;
+ }
+
+ /* write back original data */
+ do_write (dev, save_ptr, got,
+ block_size, currently_testing);
+ save_ptr += got * block_size;
+
+ currently_testing += got;
+ test_ptr += got * block_size;
+ read_ptr += got * block_size;
+ try -= got;
+ }
+
+ /* empty the buffer so it can be reused */
+ num_saved = 0;
+ buf_used = 0;
+ save_ptr = save_base;
+ test_ptr = test_base;
+ currently_testing = save_currently_testing;
+ }
+ num_blocks = 0;
+ alarm(0);
+ if (s_flag || v_flag > 1)
+ fputs(_(done_string), stderr);
+
+ flush_bufs();
+ }
+ uncapture_terminate();
+ fflush(stderr);
+ free(blkbuf);
+ free(test_record);
+
+ ext2fs_badblocks_list_iterate_end(bb_iter);
+
+ return bb_count;
+}
+
+static void check_mount(char *device_name)
+{
+ errcode_t retval;
+ int mount_flags;
+
+ retval = ext2fs_check_if_mounted(device_name, &mount_flags);
+ if (retval) {
+ com_err("ext2fs_check_if_mount", retval,
+ _("while determining whether %s is mounted."),
+ device_name);
+ return;
+ }
+ if (mount_flags & EXT2_MF_MOUNTED) {
+ fprintf(stderr, _("%s is mounted; "), device_name);
+ if (force) {
+ fputs(_("badblocks forced anyway. "
+ "Hope /etc/mtab is incorrect.\n"), stderr);
+ return;
+ }
+ abort_badblocks:
+ fputs(_("it's not safe to run badblocks!\n"), stderr);
+ exit(1);
+ }
+
+ if ((mount_flags & EXT2_MF_BUSY) && !exclusive_ok) {
+ fprintf(stderr, _("%s is apparently in use by the system; "),
+ device_name);
+ if (force)
+ fputs(_("badblocks forced anyway.\n"), stderr);
+ else
+ goto abort_badblocks;
+ }
+
+}
+
+/*
+ * This function will convert a string to an unsigned long, printing
+ * an error message if it fails, and returning success or failure in err.
+ */
+static unsigned int parse_uint(const char *str, const char *descr)
+{
+ char *tmp;
+ unsigned long ret;
+
+ errno = 0;
+ ret = strtoul(str, &tmp, 0);
+ if (*tmp || errno || (ret > UINT_MAX) ||
+ (ret == ULONG_MAX && errno == ERANGE)) {
+ com_err (program_name, 0, _("invalid %s - %s"), descr, str);
+ exit (1);
+ }
+ return ret;
+}
+
+int main (int argc, char ** argv)
+{
+ int c;
+ char * device_name;
+ char * host_device_name = NULL;
+ char * input_file = NULL;
+ char * output_file = NULL;
+ FILE * in = NULL;
+ int block_size = 1024;
+ unsigned int blocks_at_once = 64;
+ blk64_t last_block, first_block;
+ int num_passes = 0;
+ int passes_clean = 0;
+ int dev;
+ errcode_t errcode;
+ unsigned int pattern;
+ unsigned int (*test_func)(int, blk_t,
+ int, blk_t,
+ unsigned int);
+ int open_flag;
+ long sysval;
+ blk64_t inblk;
+
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+ srandom((unsigned int)time(NULL)); /* simple randomness is enough */
+ test_func = test_ro;
+
+ /* Determine the system page size if possible */
+#ifdef HAVE_SYSCONF
+#if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
+#define _SC_PAGESIZE _SC_PAGE_SIZE
+#endif
+#ifdef _SC_PAGESIZE
+ sysval = sysconf(_SC_PAGESIZE);
+ if (sysval > 0)
+ sys_page_size = sysval;
+#endif /* _SC_PAGESIZE */
+#endif /* HAVE_SYSCONF */
+
+ if (argc && *argv)
+ program_name = *argv;
+ while ((c = getopt (argc, argv, "b:d:e:fi:o:svwnc:p:h:t:BX")) != EOF) {
+ switch (c) {
+ case 'b':
+ block_size = parse_uint(optarg, "block size");
+ break;
+ case 'f':
+ force++;
+ break;
+ case 'i':
+ input_file = optarg;
+ break;
+ case 'o':
+ output_file = optarg;
+ break;
+ case 's':
+ s_flag = 1;
+ break;
+ case 'v':
+ v_flag++;
+ break;
+ case 'w':
+ if (w_flag)
+ exclusive_usage();
+ test_func = test_rw;
+ w_flag = 1;
+ break;
+ case 'n':
+ if (w_flag)
+ exclusive_usage();
+ test_func = test_nd;
+ w_flag = 2;
+ break;
+ case 'c':
+ blocks_at_once = parse_uint(optarg, "blocks at once");
+ break;
+ case 'e':
+ max_bb = parse_uint(optarg, "max bad block count");
+ break;
+ case 'd':
+ d_flag = parse_uint(optarg, "read delay factor");
+ break;
+ case 'p':
+ num_passes = parse_uint(optarg,
+ "number of clean passes");
+ break;
+ case 'h':
+ host_device_name = optarg;
+ break;
+ case 't':
+ if (t_flag + 1 > t_max) {
+ unsigned int *t_patts_new;
+
+ t_patts_new = realloc(t_patts, sizeof(int) *
+ (t_max + T_INC));
+ if (!t_patts_new) {
+ com_err(program_name, ENOMEM,
+ _("can't allocate memory for "
+ "test_pattern - %s"),
+ optarg);
+ exit(1);
+ }
+ t_patts = t_patts_new;
+ t_max += T_INC;
+ }
+ if (!strcmp(optarg, "r") || !strcmp(optarg,"random")) {
+ t_patts[t_flag++] = ~0;
+ } else {
+ pattern = parse_uint(optarg, "test pattern");
+ if (pattern == (unsigned int) ~0)
+ pattern = 0xffff;
+ t_patts[t_flag++] = pattern;
+ }
+ break;
+ case 'B':
+ use_buffered_io = 1;
+ break;
+ case 'X':
+ exclusive_ok++;
+ break;
+ default:
+ usage();
+ }
+ }
+ if (!w_flag) {
+ if (t_flag > 1) {
+ com_err(program_name, 0, "%s",
+ _("Maximum of one test_pattern may be "
+ "specified in read-only mode"));
+ exit(1);
+ }
+ if (t_patts && (t_patts[0] == (unsigned int) ~0)) {
+ com_err(program_name, 0, "%s",
+ _("Random test_pattern is not allowed "
+ "in read-only mode"));
+ exit(1);
+ }
+ }
+ if (optind > argc - 1)
+ usage();
+ device_name = argv[optind++];
+ if (optind > argc - 1) {
+ errcode = ext2fs_get_device_size2(device_name,
+ block_size,
+ &last_block);
+ if (errcode == EXT2_ET_UNIMPLEMENTED) {
+ com_err(program_name, 0, "%s",
+ _("Couldn't determine device size; you "
+ "must specify\nthe size manually\n"));
+ exit(1);
+ }
+ if (errcode) {
+ com_err(program_name, errcode, "%s",
+ _("while trying to determine device size"));
+ exit(1);
+ }
+ } else {
+ errno = 0;
+ last_block = parse_uint(argv[optind], _("last block"));
+ last_block++;
+ optind++;
+ }
+ if (optind <= argc-1) {
+ errno = 0;
+ first_block = parse_uint(argv[optind], _("first block"));
+ } else first_block = 0;
+ if (first_block >= last_block) {
+ com_err (program_name, 0, _("invalid starting block (%llu): must be less than %llu"),
+ first_block, last_block);
+ exit (1);
+ }
+ /* ext2 badblocks file can't handle large values */
+ if (last_block >> 32) {
+ com_err(program_name, EOVERFLOW,
+ _("invalid end block (%llu): must be 32-bit value"),
+ last_block);
+ exit(1);
+ }
+ if (w_flag)
+ check_mount(device_name);
+
+ gettimeofday(&time_start, 0);
+ open_flag = O_LARGEFILE | (w_flag ? O_RDWR : O_RDONLY);
+ dev = open (device_name, open_flag);
+ if (dev == -1) {
+ com_err (program_name, errno, _("while trying to open %s"),
+ device_name);
+ exit (1);
+ }
+ if (host_device_name) {
+ host_dev = open (host_device_name, open_flag);
+ if (host_dev == -1) {
+ com_err (program_name, errno,
+ _("while trying to open %s"),
+ host_device_name);
+ exit (1);
+ }
+ } else
+ host_dev = dev;
+ if (input_file) {
+ if (strcmp (input_file, "-") == 0)
+ in = stdin;
+ else {
+ in = fopen (input_file, "r");
+ if (in == NULL)
+ {
+ com_err (program_name, errno,
+ _("while trying to open %s"),
+ input_file);
+ exit (1);
+ }
+ }
+ }
+ if (output_file && strcmp (output_file, "-") != 0)
+ {
+ out = fopen (output_file, "w");
+ if (out == NULL)
+ {
+ com_err (program_name, errno,
+ _("while trying to open %s"),
+ output_file);
+ exit (1);
+ }
+ }
+ else
+ out = stdout;
+
+ errcode = ext2fs_badblocks_list_create(&bb_list,0);
+ if (errcode) {
+ com_err(program_name, errcode, "%s",
+ _("while creating in-memory bad blocks list"));
+ exit (1);
+ }
+
+ if (in) {
+ for(;;) {
+ switch (fscanf(in, "%llu\n", &inblk)) {
+ case 0:
+ com_err(program_name, 0, "%s",
+ _("input file - bad format"));
+ exit (1);
+ case EOF:
+ break;
+ default:
+ if (inblk >> 32) {
+ com_err(program_name,
+ EOVERFLOW, "%s",
+ _("while adding to in-memory "
+ "bad block list"));
+ exit(1);
+ }
+ next_bad = inblk;
+ errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
+ if (errcode) {
+ com_err(program_name, errcode,
+ "%s",
+ _("while adding to in-memory "
+ "bad block list"));
+ exit (1);
+ }
+ continue;
+ }
+ break;
+ }
+
+ if (in != stdin)
+ fclose (in);
+ }
+
+ do {
+ unsigned int bb_count;
+
+ bb_count = test_func(dev, last_block, block_size,
+ first_block, blocks_at_once);
+ if (bb_count)
+ passes_clean = 0;
+ else
+ ++passes_clean;
+
+ if (v_flag)
+ fprintf(stderr,
+ _("Pass completed, %u bad blocks found. (%d/%d/%d errors)\n"),
+ bb_count, num_read_errors, num_write_errors, num_corruption_errors);
+
+ } while (passes_clean < num_passes);
+
+ close (dev);
+ if (out != stdout)
+ fclose (out);
+ free(t_patts);
+ return 0;
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/base_device.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/base_device.c
new file mode 100644
index 0000000..b2ce138
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/base_device.c
@@ -0,0 +1,170 @@
+/*
+ * base_device.c
+ *
+ * Return the "base device" given a particular device; this is used to
+ * assure that we only fsck one partition on a particular drive at any
+ * one time. Otherwise, the disk heads will be seeking all over the
+ * place. If the base device can not be determined, return NULL.
+ *
+ * The base_device() function returns an allocated string which must
+ * be freed.
+ *
+ * Written by Theodore Ts'o, <tytso@mit.edu>
+ *
+ * Copyright (C) 2000 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+#include "config.h"
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <ctype.h>
+#include <string.h>
+
+#include "fsck.h"
+
+/*
+ * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
+ * pathames.
+ */
+static const char *devfs_hier[] = {
+ "host", "bus", "target", "lun", 0
+};
+
+char *base_device(const char *device)
+{
+ char *str, *cp;
+ const char **hier, *disk;
+ int len;
+
+ str = malloc(strlen(device)+1);
+ if (!str)
+ return NULL;
+ strcpy(str, device);
+ cp = str;
+
+ /* Skip over /dev/; if it's not present, give up. */
+ if (strncmp(cp, "/dev/", 5) != 0)
+ goto errout;
+ cp += 5;
+
+ /* Skip over /dev/dsk/... */
+ if (strncmp(cp, "dsk/", 4) == 0)
+ cp += 4;
+
+ /*
+ * For md devices, we treat them all as if they were all
+ * on one disk, since we don't know how to parallelize them.
+ */
+ if (cp[0] == 'm' && cp[1] == 'd') {
+ *(cp+2) = 0;
+ return str;
+ }
+
+ /* Handle DAC 960 devices */
+ if (strncmp(cp, "rd/", 3) == 0) {
+ cp += 3;
+ if (cp[0] != 'c' || cp[2] != 'd' ||
+ !isdigit(cp[1]) || !isdigit(cp[3]))
+ goto errout;
+ *(cp+4) = 0;
+ return str;
+ }
+
+ /* Now let's handle /dev/hd* and /dev/sd* devices.... */
+ if ((cp[0] == 'h' || cp[0] == 's') && (cp[1] == 'd')) {
+ cp += 2;
+ /* If there's a single number after /dev/hd, skip it */
+ if (isdigit(*cp))
+ cp++;
+ /* What follows must be an alpha char, or give up */
+ if (!isalpha(*cp))
+ goto errout;
+ *(cp + 1) = 0;
+ return str;
+ }
+
+ /* Now let's handle devfs (ugh) names */
+ len = 0;
+ if (strncmp(cp, "ide/", 4) == 0)
+ len = 4;
+ if (strncmp(cp, "scsi/", 5) == 0)
+ len = 5;
+ if (len) {
+ cp += len;
+ /*
+ * Now we proceed down the expected devfs hierarchy.
+ * i.e., .../host1/bus2/target3/lun4/...
+ * If we don't find the expected token, followed by
+ * some number of digits at each level, abort.
+ */
+ for (hier = devfs_hier; *hier; hier++) {
+ len = strlen(*hier);
+ if (strncmp(cp, *hier, len) != 0)
+ goto errout;
+ cp += len;
+ while (*cp != '/' && *cp != 0) {
+ if (!isdigit(*cp))
+ goto errout;
+ cp++;
+ }
+ cp++;
+ }
+ *(cp - 1) = 0;
+ return str;
+ }
+
+ /* Now handle devfs /dev/disc or /dev/disk names */
+ disk = 0;
+ if (strncmp(cp, "discs/", 6) == 0)
+ disk = "disc";
+ else if (strncmp(cp, "disks/", 6) == 0)
+ disk = "disk";
+ if (disk) {
+ cp += 6;
+ if (strncmp(cp, disk, 4) != 0)
+ goto errout;
+ cp += 4;
+ while (*cp != '/' && *cp != 0) {
+ if (!isdigit(*cp))
+ goto errout;
+ cp++;
+ }
+ *cp = 0;
+ return str;
+ }
+
+errout:
+ free(str);
+ return NULL;
+}
+
+#ifdef DEBUG
+int main(int argc, char** argv)
+{
+ const char *base;
+ char buf[256], *cp;
+
+ while (1) {
+ if (fgets(buf, sizeof(buf), stdin) == NULL)
+ break;
+ cp = strchr(buf, '\n');
+ if (cp)
+ *cp = 0;
+ cp = strchr(buf, '\t');
+ if (cp)
+ *cp = 0;
+ base = base_device(buf);
+ printf("%s\t%s\n", buf, base ? base : "NONE");
+ }
+ exit(0);
+}
+#endif
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/base_device.tst b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/base_device.tst
new file mode 100644
index 0000000..609a58d
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/base_device.tst
@@ -0,0 +1,16 @@
+/dev/hda7 /dev/hda
+/dev/sda1 /dev/sda
+/dev/hda /dev/hda
+/dev/sda /dev/sda
+/dev/dsk/hda6 /dev/dsk/hda
+/dev/dsk/sda5 /dev/dsk/sda
+/dev/md4 /dev/md
+/dev/md/4 /dev/md
+/dev/ide/host0/bus1/target2/lun3 /dev/ide/host0/bus1/target2/lun3
+/dev/ide/host0/bus1/target2/lun3/part10 /dev/ide/host0/bus1/target2/lun3
+/dev/ide/host0/bus1/target2/lun3/ /dev/ide/host0/bus1/target2/lun3
+/dev/disks/disk2/part2 /dev/disks/disk2
+/dev/disks/disk2/ /dev/disks/disk2
+/dev/disks/disk2 /dev/disks/disk2
+/dev/discs/disc1/part10 /dev/discs/disc1
+/dev/discs/disc1/ /dev/discs/disc1
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/blkid.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/blkid.8.in
new file mode 100644
index 0000000..9c42686
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/blkid.8.in
@@ -0,0 +1,164 @@
+.\" Copyright 2000 Andreas Dilger (adilger@turbolinux.com)
+.\"
+.\" This man page was created for blkid from e2fsprogs-1.25.
+.\"
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.\" Based on uuidgen, Mon Sep 17 10:42:12 2000, Andreas Dilger
+.TH BLKID 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+blkid \- command\-line utility to locate/print block device attributes
+.SH SYNOPSIS
+.B blkid
+[
+.B \-ghlLv
+]
+[
+[
+.B \-c
+.I cachefile
+]
+.B \-w
+.I writecachefile
+]
+[
+.B \-o
+.I format
+]
+[
+.B \-s
+.I tag
+]
+[
+.B \-t
+.IR NAME = value
+]
+[
+.I device ...
+]
+.SH DESCRIPTION
+The
+.B blkid
+program is the command-line interface to working with
+.BR libblkid (3)
+library. It can determine the type of content (e.g. filesystem, swap)
+a block device holds, and also attributes (tokens, NAME=value pairs)
+from the content metadata (e.g. LABEL or UUID fields).
+.PP
+.B blkid
+has two main forms of operation: either searching for a device with a
+specific NAME=value pair, or displaying NAME=value pairs for one or
+more devices.
+.SH OPTIONS
+.TP
+.BI \-c " cachefile"
+Read from
+.I cachefile
+instead of reading from the default cache file
+.IR /etc/blkid.tab .
+If you want to start with a clean cache (i.e. don't report devices previously
+scanned but not necessarily available at this time), specify
+.IR /dev/null .
+.TP
+.B \-g
+Perform a garbage collection pass on the blkid cache to remove
+devices which no longer exist.
+.TP
+.B \-h
+Display a usage message and exit.
+.TP
+.B \-l
+Look up one device that matches the search parameter specified using
+the
+.B \-t
+option. If there are multiple devices that match the specified search
+parameter, then the device with the highest priority is returned, and/or
+the first device found at a given priority. Device types in order of
+decreasing priority are Device Mapper, EVMS, LVM, MD, and finally regular
+block devices. If this option is not specified,
+.B blkid
+will print all of the devices that match the search parameter.
+.TP
+.BI \-o " format"
+Display
+.BR blkid 's
+output using the specified format. The
+.I format
+parameter may be
+.I full
+(the default),
+.I value
+(only print the value of the tags),
+.I list
+(print the devices in a user-friendly format),
+or
+.I device
+(only print the device name).
+.TP
+.B \-L
+Print the devices in a user-friendly list format. This is the
+equivalent of using the option \fB-o list\fR.
+.TP
+.BI \-s " tag"
+For each (specified) device, show only the tags that match
+.IR tag .
+It is possible to specify multiple
+.B \-s
+options. If no tag is specified, then all tokens are shown for all
+(specified) devices.
+In order to just refresh the cache without showing any tokens, use
+.B "-s none"
+with no other options.
+.TP
+.BI \-t " NAME" = "value"
+Search for block devices with tokens named
+.I NAME
+that have the value
+.IR value ,
+and display any devices which are found.
+Common values for
+.I NAME
+include
+.BR TYPE ,
+.BR LABEL ,
+and
+.BR UUID .
+If there are no devices specified on the command line, all block devices
+will be searched; otherwise only the specified devices are searched.
+.TP
+.B \-v
+Display version number and exit.
+.TP
+.BI \-w " writecachefile"
+Write the device cache to
+.I writecachefile
+instead of writing it to the default cache file
+.IR /etc/blkid.tab .
+If you don't want to save the cache to the default file, specify
+.IR /dev/null.
+If not specified it will be the same file as that given by the
+.B \-c
+option.
+.TP
+.I device
+Display tokens from only the specified device. It is possible to
+give multiple
+.I device
+options on the command line. If none is given, all devices which
+appear in
+.I /proc/partitions
+are shown, if they are recognized.
+.SH "RETURN CODE"
+If the specified token was found, or if any tags were shown from (specified)
+devices, 0 is returned. If the specified token was not found, or no
+(specified) devices could be identified, an exit code of 2 is returned.
+For usage or other errors, an exit code of 4 is returned.
+.SH AUTHOR
+.B blkid
+was written by Andreas Dilger for libblkid.
+.SH AVAILABILITY
+.B blkid
+is part the e2fsprogs package since version 1.26 and is available from
+http://e2fsprogs.sourceforge.net.
+.SH "SEE ALSO"
+.BR libblkid (3)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/blkid.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/blkid.c
new file mode 100644
index 0000000..a4a8db0
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/blkid.c
@@ -0,0 +1,427 @@
+/*
+ * blkid.c - User command-line interface for libblkid
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+#ifdef HAVE_TERMIO_H
+#include <termio.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern int getopt(int argc, char * const argv[], const char *optstring);
+extern char *optarg;
+extern int optind;
+#endif
+
+#define OUTPUT_VALUE_ONLY 0x0001
+#define OUTPUT_DEVICE_ONLY 0x0002
+#define OUTPUT_PRETTY_LIST 0x0004
+
+#include "ext2fs/ext2fs.h"
+#include "blkid/blkid.h"
+
+const char *progname = "blkid";
+
+static void print_version(FILE *out)
+{
+ fprintf(out, "%s %s (%s)\n", progname, BLKID_VERSION, BLKID_DATE);
+}
+
+static void usage(int error)
+{
+ FILE *out = error ? stderr : stdout;
+
+ print_version(out);
+ fprintf(out,
+ "usage:\t%s [-c <file>] [-ghlLv] [-o format] "
+ "[-s <tag>] [-t <token>]\n [-w <file>] [dev ...]\n"
+ "\t-c\tcache file (default: /etc/blkid.tab, /dev/null = none)\n"
+ "\t-h\tprint this usage message and exit\n"
+ "\t-g\tgarbage collect the blkid cache\n"
+ "\t-s\tshow specified tag(s) (default show all tags)\n"
+ "\t-t\tfind device with a specific token (NAME=value pair)\n"
+ "\t-l\tlookup the the first device with arguments specified by -t\n"
+ "\t-v\tprint version and exit\n"
+ "\t-w\twrite cache to different file (/dev/null = no write)\n"
+ "\tdev\tspecify device(s) to probe (default: all devices)\n",
+ progname);
+ exit(error);
+}
+
+/*
+ * 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)
+{
+ unsigned char ch;
+
+ if (len < 0)
+ len = strlen(cp);
+
+ while (len--) {
+ ch = *cp++;
+ if (ch > 128) {
+ fputs("M-", stdout);
+ ch -= 128;
+ }
+ if ((ch < 32) || (ch == 0x7f)) {
+ fputc('^', stdout);
+ ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
+ }
+ fputc(ch, stdout);
+ }
+}
+
+static int get_terminal_width(void)
+{
+#ifdef TIOCGSIZE
+ struct ttysize t_win;
+#endif
+#ifdef TIOCGWINSZ
+ struct winsize w_win;
+#endif
+ const char *cp;
+
+#ifdef TIOCGSIZE
+ if (ioctl (0, TIOCGSIZE, &t_win) == 0)
+ return (t_win.ts_cols);
+#endif
+#ifdef TIOCGWINSZ
+ if (ioctl (0, TIOCGWINSZ, &w_win) == 0)
+ return (w_win.ws_col);
+#endif
+ cp = getenv("COLUMNS");
+ if (cp)
+ return strtol(cp, NULL, 10);
+ return 80;
+}
+
+static int pretty_print_word(const char *str, int max_len,
+ int left_len, int overflow_nl)
+{
+ int len = strlen(str) + left_len;
+ int ret = 0;
+
+ fputs(str, stdout);
+ if (overflow_nl && len > max_len) {
+ fputc('\n', stdout);
+ len = 0;
+ } else if (len > max_len)
+ ret = len - max_len;
+ do
+ fputc(' ', stdout);
+ while (len++ < max_len);
+ return ret;
+}
+
+static void pretty_print_line(const char *device, const char *fs_type,
+ const char *label, const char *mtpt,
+ const char *uuid)
+{
+ static int device_len = 10, fs_type_len = 7;
+ static int label_len = 8, mtpt_len = 14;
+ static int term_width = -1;
+ int len, w;
+
+ if (term_width < 0)
+ term_width = get_terminal_width();
+
+ if (term_width > 80) {
+ term_width -= 80;
+ w = term_width / 10;
+ if (w > 8)
+ w = 8;
+ term_width -= 2*w;
+ label_len += w;
+ fs_type_len += w;
+ w = term_width/2;
+ device_len += w;
+ mtpt_len +=w;
+ }
+
+ len = pretty_print_word(device, device_len, 0, 1);
+ len = pretty_print_word(fs_type, fs_type_len, len, 0);
+ len = pretty_print_word(label, label_len, len, 0);
+ len = pretty_print_word(mtpt, mtpt_len, len, 0);
+ fputs(uuid, stdout);
+ fputc('\n', stdout);
+}
+
+static void pretty_print_dev(blkid_dev dev)
+{
+ blkid_tag_iterate iter;
+ const char *type, *value, *devname;
+ const char *uuid = "", *fs_type = "", *label = "";
+ int len, mount_flags;
+ char mtpt[80];
+ errcode_t retval;
+
+ if (dev == NULL) {
+ pretty_print_line("device", "fs_type", "label",
+ "mount point", "UUID");
+ for (len=get_terminal_width()-1; len > 0; len--)
+ fputc('-', stdout);
+ fputc('\n', stdout);
+ return;
+ }
+
+ devname = blkid_dev_devname(dev);
+ if (access(devname, F_OK))
+ return;
+
+ /* Get the uuid, label, type */
+ iter = blkid_tag_iterate_begin(dev);
+ while (blkid_tag_next(iter, &type, &value) == 0) {
+ if (!strcmp(type, "UUID"))
+ uuid = value;
+ if (!strcmp(type, "TYPE"))
+ fs_type = value;
+ if (!strcmp(type, "LABEL"))
+ label = value;
+ }
+ blkid_tag_iterate_end(iter);
+
+ /* Get the mount point */
+ mtpt[0] = 0;
+ retval = ext2fs_check_mount_point(devname, &mount_flags,
+ mtpt, sizeof(mtpt));
+ if (retval == 0) {
+ if (mount_flags & EXT2_MF_MOUNTED) {
+ if (!mtpt[0])
+ strcpy(mtpt, "(mounted, mtpt unknown)");
+ } else if (mount_flags & EXT2_MF_BUSY)
+ strcpy(mtpt, "(in use)");
+ else
+ strcpy(mtpt, "(not mounted)");
+ }
+
+ pretty_print_line(devname, fs_type, label, mtpt, uuid);
+}
+
+static void print_tags(blkid_dev dev, char *show[], int numtag, int output)
+{
+ blkid_tag_iterate iter;
+ const char *type, *value;
+ int i, first = 1;
+
+ if (!dev)
+ return;
+
+ if (output & OUTPUT_PRETTY_LIST) {
+ pretty_print_dev(dev);
+ return;
+ }
+
+ if (output & OUTPUT_DEVICE_ONLY) {
+ printf("%s\n", blkid_dev_devname(dev));
+ return;
+ }
+
+ iter = blkid_tag_iterate_begin(dev);
+ while (blkid_tag_next(iter, &type, &value) == 0) {
+ if (numtag && show) {
+ for (i=0; i < numtag; i++)
+ if (!strcmp(type, show[i]))
+ break;
+ if (i >= numtag)
+ continue;
+ }
+ if (output & OUTPUT_VALUE_ONLY) {
+ fputs(value, stdout);
+ fputc('\n', stdout);
+ } else {
+ if (first) {
+ printf("%s: ", blkid_dev_devname(dev));
+ first = 0;
+ }
+ fputs(type, stdout);
+ fputs("=\"", stdout);
+ safe_print(value, -1);
+ fputs("\" ", stdout);
+ }
+ }
+ blkid_tag_iterate_end(iter);
+
+ if (!first && !(output & OUTPUT_VALUE_ONLY))
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ blkid_cache cache = NULL;
+ char *devices[128] = { NULL, };
+ char *show[128] = { NULL, };
+ char *search_type = NULL, *search_value = NULL;
+ char *read = NULL;
+ char *write = NULL;
+ unsigned int numdev = 0, numtag = 0;
+ int version = 0;
+ int err = 4;
+ unsigned int i;
+ int output_format = 0;
+ int lookup = 0, gc = 0;
+ int c;
+
+ while ((c = getopt (argc, argv, "c:f:ghlLo:s:t:w:v")) != EOF)
+ switch (c) {
+ case 'c':
+ if (optarg && !*optarg)
+ read = NULL;
+ else
+ read = optarg;
+ if (!write)
+ write = read;
+ break;
+ case 'l':
+ lookup++;
+ break;
+ case 'L':
+ output_format = OUTPUT_PRETTY_LIST;
+ break;
+ case 'g':
+ gc = 1;
+ break;
+ case 'o':
+ if (!strcmp(optarg, "value"))
+ output_format = OUTPUT_VALUE_ONLY;
+ else if (!strcmp(optarg, "device"))
+ output_format = OUTPUT_DEVICE_ONLY;
+ else if (!strcmp(optarg, "list"))
+ output_format = OUTPUT_PRETTY_LIST;
+ else if (!strcmp(optarg, "full"))
+ output_format = 0;
+ else {
+ fprintf(stderr, "Invalid output format %s. "
+ "Choose from value,\n\t"
+ "device, list, or full\n", optarg);
+ exit(1);
+ }
+ break;
+ case 's':
+ if (numtag >= sizeof(show) / sizeof(*show)) {
+ fprintf(stderr, "Too many tags specified\n");
+ usage(err);
+ }
+ show[numtag++] = optarg;
+ break;
+ case 't':
+ if (search_type) {
+ fprintf(stderr, "Can only search for "
+ "one NAME=value pair\n");
+ usage(err);
+ }
+ if (blkid_parse_tag_string(optarg,
+ &search_type,
+ &search_value)) {
+ fprintf(stderr, "-t needs NAME=value pair\n");
+ usage(err);
+ }
+ break;
+ case 'v':
+ version = 1;
+ break;
+ case 'w':
+ if (optarg && !*optarg)
+ write = NULL;
+ else
+ write = optarg;
+ break;
+ case 'h':
+ err = 0;
+ default:
+ usage(err);
+ }
+
+ while (optind < argc)
+ devices[numdev++] = argv[optind++];
+
+ if (version) {
+ print_version(stdout);
+ goto exit;
+ }
+
+ if (blkid_get_cache(&cache, read) < 0)
+ goto exit;
+
+ err = 2;
+ if (gc) {
+ blkid_gc_cache(cache);
+ goto exit;
+ }
+ if (output_format & OUTPUT_PRETTY_LIST)
+ pretty_print_dev(NULL);
+
+ if (lookup) {
+ blkid_dev dev;
+
+ if (!search_type) {
+ fprintf(stderr, "The lookup option requires a "
+ "search type specified using -t\n");
+ exit(1);
+ }
+ /* Load any additional devices not in the cache */
+ for (i = 0; i < numdev; i++)
+ blkid_get_dev(cache, devices[i], BLKID_DEV_NORMAL);
+
+ if ((dev = blkid_find_dev_with_tag(cache, search_type,
+ search_value))) {
+ print_tags(dev, show, numtag, output_format);
+ err = 0;
+ }
+ /* If we didn't specify a single device, show all available devices */
+ } else if (!numdev) {
+ blkid_dev_iterate iter;
+ blkid_dev dev;
+
+ blkid_probe_all(cache);
+
+ iter = blkid_dev_iterate_begin(cache);
+ blkid_dev_set_search(iter, search_type, search_value);
+ while (blkid_dev_next(iter, &dev) == 0) {
+ dev = blkid_verify(cache, dev);
+ if (!dev)
+ continue;
+ print_tags(dev, show, numtag, output_format);
+ err = 0;
+ }
+ blkid_dev_iterate_end(iter);
+ /* Add all specified devices to cache (optionally display tags) */
+ } else for (i = 0; i < numdev; i++) {
+ blkid_dev dev = blkid_get_dev(cache, devices[i],
+ BLKID_DEV_NORMAL);
+
+ if (dev) {
+ if (search_type &&
+ !blkid_dev_has_tag(dev, search_type,
+ search_value))
+ continue;
+ print_tags(dev, show, numtag, output_format);
+ err = 0;
+ }
+ }
+
+exit:
+ free(search_type);
+ free(search_value);
+ blkid_put_cache(cache);
+ return err;
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/chattr.1.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/chattr.1.in
new file mode 100644
index 0000000..932ef4b
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/chattr.1.in
@@ -0,0 +1,182 @@
+.\" -*- nroff -*-
+.TH CHATTR 1 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+chattr \- change file attributes on a Linux file system
+.SH SYNOPSIS
+.B chattr
+[
+.B \-RVf
+]
+[
+.B \-v
+.I version
+]
+[
+.I mode
+]
+.I files...
+.SH DESCRIPTION
+.B chattr
+changes the file attributes on a Linux file system.
+.PP
+The format of a symbolic mode is +-=[acdeijstuACDST].
+.PP
+The operator `+' causes the selected attributes to be added to the
+existing attributes of the files; `-' causes them to be removed; and
+`=' causes them to be the only attributes that the files have.
+.PP
+The letters `acdeijstuACDST' select the new attributes for the files:
+append only (a), compressed (c), no dump (d), extent format (e), immutable (i),
+data journalling (j), secure deletion (s), no tail-merging (t),
+undeletable (u), no atime updates (A), no copy on write (C),
+synchronous directory updates (D), synchronous updates (S),
+and top of directory hierarchy (T).
+.PP
+The following attributes are read-only, and may be listed by
+.BR lsattr (1)
+but not modified by chattr: huge file (h), compression error (E),
+indexed directory (I), compression raw access (X), and compressed dirty
+file (Z).
+.SH OPTIONS
+.TP
+.B \-R
+Recursively change attributes of directories and their contents.
+.TP
+.B \-V
+Be verbose with chattr's output and print the program version.
+.TP
+.B \-f
+Suppress most error messages.
+.TP
+.BI \-v " version"
+Set the file's version/generation number.
+.SH ATTRIBUTES
+When a file with the 'A' attribute set is accessed, its atime record is
+not modified. This avoids a certain amount of disk I/O for laptop
+systems.
+.PP
+A file with the `a' attribute set can only be open in append mode for writing.
+Only the superuser or a process possessing the CAP_LINUX_IMMUTABLE
+capability can set or clear this attribute.
+.PP
+A file with the `c' attribute set is automatically compressed on the disk
+by the kernel. A read from this file returns uncompressed data. A write to
+this file compresses data before storing them on the disk. Note: please
+make sure to read the bugs and limitations section at the end of this
+document.
+.PP
+A file with the 'C' attribute set will not be subject to copy-on-write
+updates. This flag is only supported on file systems which perform
+copy-on-write. (Note: For btrfs, the 'C' flag should be
+set on new or empty files. If it is set on a file which already has
+data blocks, it is undefined when the blocks assigned to the file will
+be fully stable. If the 'C' flag is set on a directory, it will have no
+effect on the directory, but new files created in that directory will
+the No_COW attribute.)
+.PP
+When a directory with the `D' attribute set is modified,
+the changes are written synchronously on the disk; this is equivalent to
+the `dirsync' mount option applied to a subset of the files.
+.PP
+A file with the `d' attribute set is not candidate for backup when the
+.BR dump (8)
+program is run.
+.PP
+The 'E' attribute is used by the experimental compression patches to
+indicate that a compressed file has a compression error. It may not be
+set or reset using
+.BR chattr (1),
+although it can be displayed by
+.BR lsattr (1).
+.PP
+The 'e' attribute indicates that the file is using extents for mapping
+the blocks on disk. It may not be removed using
+.BR chattr (1).
+.PP
+The 'I' attribute is used by the htree code to indicate that a directory
+is being indexed using hashed trees. It may not be set or reset using
+.BR chattr (1),
+although it can be displayed by
+.BR lsattr (1).
+.PP
+The 'h' attribute indicates the file is storing its blocks in units of the
+filesystem blocksize instead of in units of sectors, and means that the file
+is (or at one time was) larger than 2TB. It may not be set or reset using
+.BR chattr (1),
+although it can be displayed by
+.BR lsattr (1).
+.PP
+A file with the `i' attribute cannot be modified: it cannot be deleted or
+renamed, no link can be created to this file and no data can be written
+to the file. Only the superuser or a process possessing the
+CAP_LINUX_IMMUTABLE capability can set or clear this attribute.
+.PP
+A file with the `j' attribute has all of its data written to the ext3
+journal before being written to the file itself, if the filesystem is
+mounted with the "data=ordered" or "data=writeback" options. When the
+filesystem is mounted with the "data=journal" option all file data
+is already journalled and this attribute has no effect. Only
+the superuser or a process possessing the CAP_SYS_RESOURCE
+capability can set or clear this attribute.
+.PP
+When a file with the `s' attribute set is deleted, its blocks are zeroed
+and written back to the disk. Note: please make sure to read the bugs
+and limitations section at the end of this document.
+.PP
+When a file with the `S' attribute set is modified,
+the changes are written synchronously on the disk; this is equivalent to
+the `sync' mount option applied to a subset of the files.
+.PP
+A directory with the 'T' attribute will be deemed to be the top of
+directory hierarchies for the purposes of the Orlov block allocator.
+This is a hint to the block allocator used by ext3 and ext4 that the
+subdirectories under this directory are not related, and thus should be
+spread apart for allocation purposes. For example it is a very good
+idea to set the 'T' attribute on the /home directory, so that /home/john
+and /home/mary are placed into separate block groups. For directories
+where this attribute is not set, the Orlov block allocator will try to
+group subdirectories closer together where possible.
+.PP
+A file with the 't' attribute will not have a partial block fragment at
+the end of the file merged with other files (for those filesystems which
+support tail-merging). This is necessary for applications such as LILO
+which read the filesystem directly, and which don't understand tail-merged
+files. Note: As of this writing, the ext2 or ext3 filesystems do not
+(yet, except in very experimental patches) support tail-merging.
+.PP
+When a file with the `u' attribute set is deleted, its contents are
+saved. This allows the user to ask for its undeletion. Note: please
+make sure to read the bugs and limitations section at the end of this
+document.
+.PP
+The 'X' attribute is used by the experimental compression patches to
+indicate that a raw contents of a compressed file can be accessed
+directly. It currently may not be set or reset using
+.BR chattr (1),
+although it can be displayed by
+.BR lsattr (1).
+.PP
+The 'Z' attribute is used by the experimental compression patches to
+indicate a compressed file is dirty. It may not be set or reset using
+.BR chattr (1),
+although it can be displayed by
+.BR lsattr (1).
+.PP
+.SH AUTHOR
+.B chattr
+was written by Remy Card <Remy.Card@linux.org>. It is currently being
+maintained by Theodore Ts'o <tytso@alum.mit.edu>.
+.SH BUGS AND LIMITATIONS
+The `c', 's', and `u' attributes are not honored
+by the ext2, ext3, and ext4 filesystems as implemented in the current
+mainline Linux kernels.
+.PP
+The `j' option is only useful if the filesystem is mounted as ext3.
+.PP
+The `D' option is only useful on Linux kernel 2.5.19 and later.
+.SH AVAILABILITY
+.B chattr
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR lsattr (1)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/chattr.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/chattr.c
new file mode 100644
index 0000000..39a6016
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/chattr.c
@@ -0,0 +1,327 @@
+/*
+ * chattr.c - Change file attributes on an ext2 file system
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30 - Creation
+ * 93/11/13 - Replace stat() calls by lstat() to avoid loops
+ * 94/02/27 - Integrated in Ted's distribution
+ * 98/12/29 - Ignore symlinks when working recursively (G M Sipe)
+ * 98/12/29 - Display version info only when -V specified (G M Sipe)
+ */
+
+#define _LARGEFILE64_SOURCE
+
+#include "config.h"
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <sys/param.h>
+#include <sys/stat.h>
+#include "ext2fs/ext2_fs.h"
+
+#ifdef __GNUC__
+#define EXT2FS_ATTR(x) __attribute__(x)
+#else
+#define EXT2FS_ATTR(x)
+#endif
+
+#ifndef S_ISLNK /* So we can compile even with gcc-warn */
+# ifdef __S_IFLNK
+# define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
+# else
+# define S_ISLNK(mode) 0
+# endif
+#endif
+
+#include "et/com_err.h"
+#include "e2p/e2p.h"
+
+#include "../version.h"
+#include "nls-enable.h"
+
+static const char * program_name = "chattr";
+
+static int add;
+static int rem;
+static int set;
+static int set_version;
+
+static unsigned long version;
+
+static int recursive;
+static int verbose;
+static int silent;
+
+static unsigned long af;
+static unsigned long rf;
+static unsigned long sf;
+
+#ifdef _LFS64_LARGEFILE
+#define LSTAT lstat64
+#define STRUCT_STAT struct stat64
+#else
+#define LSTAT lstat
+#define STRUCT_STAT struct stat
+#endif
+
+static void usage(void)
+{
+ fprintf(stderr,
+ _("Usage: %s [-RVf] [-+=AaCcDdeijsSu] [-v version] files...\n"),
+ program_name);
+ exit(1);
+}
+
+struct flags_char {
+ unsigned long flag;
+ char optchar;
+};
+
+static const struct flags_char flags_array[] = {
+ { EXT2_NOATIME_FL, 'A' },
+ { EXT2_SYNC_FL, 'S' },
+ { EXT2_DIRSYNC_FL, 'D' },
+ { EXT2_APPEND_FL, 'a' },
+ { EXT2_COMPR_FL, 'c' },
+ { EXT2_NODUMP_FL, 'd' },
+ { EXT4_EXTENTS_FL, 'e'},
+ { EXT2_IMMUTABLE_FL, 'i' },
+ { EXT3_JOURNAL_DATA_FL, 'j' },
+ { EXT2_SECRM_FL, 's' },
+ { EXT2_UNRM_FL, 'u' },
+ { EXT2_NOTAIL_FL, 't' },
+ { EXT2_TOPDIR_FL, 'T' },
+ { FS_NOCOW_FL, 'C' },
+ { 0, 0 }
+};
+
+static unsigned long get_flag(char c)
+{
+ const struct flags_char *fp;
+
+ for (fp = flags_array; fp->flag != 0; fp++) {
+ if (fp->optchar == c)
+ return fp->flag;
+ }
+ return 0;
+}
+
+
+static int decode_arg (int * i, int argc, char ** argv)
+{
+ char * p;
+ char * tmp;
+ unsigned long fl;
+
+ switch (argv[*i][0])
+ {
+ case '-':
+ for (p = &argv[*i][1]; *p; p++) {
+ if (*p == 'R') {
+ recursive = 1;
+ continue;
+ }
+ if (*p == 'V') {
+ verbose = 1;
+ continue;
+ }
+ if (*p == 'f') {
+ silent = 1;
+ continue;
+ }
+ if (*p == 'v') {
+ (*i)++;
+ if (*i >= argc)
+ usage ();
+ version = strtol (argv[*i], &tmp, 0);
+ if (*tmp) {
+ com_err (program_name, 0,
+ _("bad version - %s\n"),
+ argv[*i]);
+ usage ();
+ }
+ set_version = 1;
+ continue;
+ }
+ if ((fl = get_flag(*p)) == 0)
+ usage();
+ rf |= fl;
+ rem = 1;
+ }
+ break;
+ case '+':
+ add = 1;
+ for (p = &argv[*i][1]; *p; p++) {
+ if ((fl = get_flag(*p)) == 0)
+ usage();
+ af |= fl;
+ }
+ break;
+ case '=':
+ set = 1;
+ for (p = &argv[*i][1]; *p; p++) {
+ if ((fl = get_flag(*p)) == 0)
+ usage();
+ sf |= fl;
+ }
+ break;
+ default:
+ return EOF;
+ break;
+ }
+ return 1;
+}
+
+static int chattr_dir_proc(const char *, struct dirent *, void *);
+
+static int change_attributes(const char * name)
+{
+ unsigned long flags;
+ STRUCT_STAT st;
+
+ if (LSTAT (name, &st) == -1) {
+ if (!silent)
+ com_err (program_name, errno,
+ _("while trying to stat %s"), name);
+ return -1;
+ }
+
+ if (fgetflags(name, &flags) == -1) {
+ if (!silent)
+ com_err(program_name, errno,
+ _("while reading flags on %s"), name);
+ return -1;
+ }
+ if (set) {
+ if (verbose) {
+ printf (_("Flags of %s set as "), name);
+ print_flags (stdout, sf, 0);
+ printf ("\n");
+ }
+ if (fsetflags (name, sf) == -1)
+ perror (name);
+ } else {
+ if (rem)
+ flags &= ~rf;
+ if (add)
+ flags |= af;
+ if (verbose) {
+ printf(_("Flags of %s set as "), name);
+ print_flags(stdout, flags, 0);
+ printf("\n");
+ }
+ if (!S_ISDIR(st.st_mode))
+ flags &= ~EXT2_DIRSYNC_FL;
+ if (fsetflags(name, flags) == -1) {
+ if (!silent) {
+ com_err(program_name, errno,
+ _("while setting flags on %s"),
+ name);
+ }
+ return -1;
+ }
+ }
+ if (set_version) {
+ if (verbose)
+ printf (_("Version of %s set as %lu\n"), name, version);
+ if (fsetversion (name, version) == -1) {
+ if (!silent)
+ com_err (program_name, errno,
+ _("while setting version on %s"),
+ name);
+ return -1;
+ }
+ }
+ if (S_ISDIR(st.st_mode) && recursive)
+ return iterate_on_dir (name, chattr_dir_proc, NULL);
+ return 0;
+}
+
+static int chattr_dir_proc (const char * dir_name, struct dirent * de,
+ void * private EXT2FS_ATTR((unused)))
+{
+ int ret = 0;
+
+ if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) {
+ char *path;
+
+ path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1);
+ if (!path) {
+ fprintf(stderr, "%s",
+ _("Couldn't allocate path variable "
+ "in chattr_dir_proc"));
+ return -1;
+ }
+ sprintf(path, "%s/%s", dir_name, de->d_name);
+ ret = change_attributes(path);
+ free(path);
+ }
+ return ret;
+}
+
+int main (int argc, char ** argv)
+{
+ int i, j;
+ int end_arg = 0;
+ int err, retval = 0;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+ if (argc && *argv)
+ program_name = *argv;
+ i = 1;
+ while (i < argc && !end_arg) {
+ /* '--' arg should end option processing */
+ if (strcmp(argv[i], "--") == 0) {
+ i++;
+ end_arg = 1;
+ } else if (decode_arg (&i, argc, argv) == EOF)
+ end_arg = 1;
+ else
+ i++;
+ }
+ if (i >= argc)
+ usage ();
+ if (set && (add || rem)) {
+ fputs(_("= is incompatible with - and +\n"), stderr);
+ exit (1);
+ }
+ if ((rf & af) != 0) {
+ fputs("Can't both set and unset same flag.\n", stderr);
+ exit (1);
+ }
+ if (!(add || rem || set || set_version)) {
+ fputs(_("Must use '-v', =, - or +\n"), stderr);
+ exit (1);
+ }
+ if (verbose)
+ fprintf (stderr, "chattr %s (%s)\n",
+ E2FSPROGS_VERSION, E2FSPROGS_DATE);
+ for (j = i; j < argc; j++) {
+ err = change_attributes (argv[j]);
+ if (err)
+ retval = 1;
+ }
+ exit(retval);
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/dumpe2fs.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/dumpe2fs.8.in
new file mode 100644
index 0000000..befaf94
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/dumpe2fs.8.in
@@ -0,0 +1,87 @@
+.\" -*- nroff -*-
+.\" Copyright 1993, 1994, 1995 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH DUMPE2FS 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+dumpe2fs \- dump ext2/ext3/ext4 filesystem information
+.SH SYNOPSIS
+.B dumpe2fs
+[
+.B \-bfhixV
+]
+[
+.B \-o superblock=\fIsuperblock
+]
+[
+.B \-o blocksize=\fIblocksize
+]
+.I device
+.SH DESCRIPTION
+.B dumpe2fs
+prints the super block and blocks group information for the filesystem
+present on
+.I device.
+.PP
+.B Note:
+When used with a mounted filesystem, the printed
+information may be old or inconsistent.
+.SH OPTIONS
+.TP
+.B \-b
+print the blocks which are reserved as bad in the filesystem.
+.TP
+.B \-o superblock=\fIsuperblock
+use the block
+.I superblock
+when examining the filesystem.
+This option is not usually needed except by a filesystem wizard who
+is examining the remains of a very badly corrupted filesystem.
+.TP
+.B \-o blocksize=\fIblocksize
+use blocks of
+.I blocksize
+bytes when examining the filesystem.
+This option is not usually needed except by a filesystem wizard who
+is examining the remains of a very badly corrupted filesystem.
+.TP
+.B \-f
+force dumpe2fs to display a filesystem even though it may have some
+filesystem feature flags which dumpe2fs may not understand (and which
+can cause some of dumpe2fs's display to be suspect).
+.TP
+.B \-h
+only display the superblock information and not any of the block
+group descriptor detail information.
+.TP
+.B \-i
+display the filesystem data from an image file created by
+.BR e2image ,
+using
+.I device
+as the pathname to the image file.
+.TP
+.B \-x
+print the detailed group information block numbers in hexadecimal format
+.TP
+.B \-V
+print the version number of
+.B dumpe2fs
+and exit.
+.SH BUGS
+You need to know the physical filesystem structure to understand the
+output.
+.SH AUTHOR
+.B dumpe2fs
+was written by Remy Card <Remy.Card@linux.org>. It is currently being
+maintained by Theodore Ts'o <tytso@alum.mit.edu>.
+.SH AVAILABILITY
+.B dumpe2fs
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR e2fsck (8),
+.BR mke2fs (8),
+.BR tune2fs (8).
+.BR ext4 (5)
+
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/dumpe2fs.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/dumpe2fs.c
new file mode 100644
index 0000000..d4bde8e
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/dumpe2fs.c
@@ -0,0 +1,640 @@
+/*
+ * dumpe2fs.c - List the control structures of a second
+ * extended filesystem
+ *
+ * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * Copyright 1995, 1996, 1997 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/*
+ * History:
+ * 94/01/09 - Creation
+ * 94/02/27 - Ported to use the ext2fs library
+ */
+
+#include "config.h"
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ext2fs/ext2_fs.h"
+
+#include "ext2fs/ext2fs.h"
+#include "e2p/e2p.h"
+#include "jfs_user.h"
+#include <uuid/uuid.h>
+
+#include "../version.h"
+#include "nls-enable.h"
+
+#define in_use(m, x) (ext2fs_test_bit ((x), (m)))
+
+static const char * program_name = "dumpe2fs";
+static char * device_name = NULL;
+static int hex_format = 0;
+static int blocks64 = 0;
+
+static void usage(void)
+{
+ fprintf (stderr, _("Usage: %s [-bfhixV] [-o superblock=<num>] "
+ "[-o blocksize=<num>] device\n"), program_name);
+ exit (1);
+}
+
+static void print_number(unsigned long long num)
+{
+ if (hex_format) {
+ if (blocks64)
+ printf("0x%08llx", num);
+ else
+ printf("0x%04llx", num);
+ } else
+ printf("%llu", num);
+}
+
+static void print_range(unsigned long long a, unsigned long long b)
+{
+ if (hex_format) {
+ if (blocks64)
+ printf("0x%08llx-0x%08llx", a, b);
+ else
+ printf("0x%04llx-0x%04llx", a, b);
+ } else
+ printf("%llu-%llu", a, b);
+}
+
+static void print_free(unsigned long group, char * bitmap,
+ unsigned long num, unsigned long offset, int ratio)
+{
+ int p = 0;
+ unsigned long i;
+ unsigned long j;
+
+ offset /= ratio;
+ offset += group * num;
+ for (i = 0; i < num; i++)
+ if (!in_use (bitmap, i))
+ {
+ if (p)
+ printf (", ");
+ print_number((i + offset) * ratio);
+ for (j = i; j < num && !in_use (bitmap, j); j++)
+ ;
+ if (--j != i) {
+ fputc('-', stdout);
+ print_number((j + offset) * ratio);
+ i = j;
+ }
+ p = 1;
+ }
+}
+
+static void print_bg_opt(int bg_flags, int mask,
+ const char *str, int *first)
+{
+ if (bg_flags & mask) {
+ if (*first) {
+ fputs(" [", stdout);
+ *first = 0;
+ } else
+ fputs(", ", stdout);
+ fputs(str, stdout);
+ }
+}
+static void print_bg_opts(ext2_filsys fs, dgrp_t i)
+{
+ int first = 1, bg_flags = 0;
+
+ if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
+ bg_flags = ext2fs_bg_flags(fs, i);
+
+ print_bg_opt(bg_flags, EXT2_BG_INODE_UNINIT, "INODE_UNINIT",
+ &first);
+ print_bg_opt(bg_flags, EXT2_BG_BLOCK_UNINIT, "BLOCK_UNINIT",
+ &first);
+ print_bg_opt(bg_flags, EXT2_BG_INODE_ZEROED, "ITABLE_ZEROED",
+ &first);
+ if (!first)
+ fputc(']', stdout);
+ fputc('\n', stdout);
+}
+
+static void print_bg_rel_offset(ext2_filsys fs, blk64_t block, int itable,
+ blk64_t first_block, blk64_t last_block)
+{
+ if ((block >= first_block) && (block <= last_block)) {
+ if (itable && block == first_block)
+ return;
+ printf(" (+%u)", (unsigned)(block - first_block));
+ } else if (fs->super->s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_FLEX_BG) {
+ dgrp_t flex_grp = ext2fs_group_of_blk2(fs, block);
+ printf(" (bg #%u + %u)", flex_grp,
+ (unsigned)(block-ext2fs_group_first_block2(fs,flex_grp)));
+ }
+}
+
+static void list_desc (ext2_filsys fs)
+{
+ unsigned long i;
+ blk64_t first_block, last_block;
+ blk64_t super_blk, old_desc_blk, new_desc_blk;
+ char *block_bitmap=NULL, *inode_bitmap=NULL;
+ const char *units = _("blocks");
+ int inode_blocks_per_group, old_desc_blocks, reserved_gdt;
+ int block_nbytes, inode_nbytes;
+ int has_super;
+ blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
+ ext2_ino_t ino_itr = 1;
+ errcode_t retval;
+
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+ units = _("clusters");
+
+ block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
+ inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
+
+ if (fs->block_map)
+ block_bitmap = malloc(block_nbytes);
+ if (fs->inode_map)
+ inode_bitmap = malloc(inode_nbytes);
+
+ inode_blocks_per_group = ((fs->super->s_inodes_per_group *
+ EXT2_INODE_SIZE(fs->super)) +
+ EXT2_BLOCK_SIZE(fs->super) - 1) /
+ EXT2_BLOCK_SIZE(fs->super);
+ reserved_gdt = fs->super->s_reserved_gdt_blocks;
+ fputc('\n', stdout);
+ first_block = fs->super->s_first_data_block;
+ if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
+ old_desc_blocks = fs->super->s_first_meta_bg;
+ else
+ old_desc_blocks = fs->desc_blocks;
+ for (i = 0; i < fs->group_desc_count; i++) {
+ first_block = ext2fs_group_first_block2(fs, i);
+ last_block = ext2fs_group_last_block2(fs, i);
+
+ ext2fs_super_and_bgd_loc2(fs, i, &super_blk,
+ &old_desc_blk, &new_desc_blk, 0);
+
+ printf (_("Group %lu: (Blocks "), i);
+ print_range(first_block, last_block);
+ fputs(")", stdout);
+ print_bg_opts(fs, i);
+ if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+ unsigned csum = ext2fs_bg_checksum(fs, i);
+ unsigned exp_csum = ext2fs_group_desc_csum(fs, i);
+
+ printf(_(" Checksum 0x%04x"), csum);
+ if (csum != exp_csum)
+ printf(_(" (EXPECTED 0x%04x)"), exp_csum);
+ printf(_(", unused inodes %u\n"),
+ ext2fs_bg_itable_unused(fs, i));
+ }
+ has_super = ((i==0) || super_blk);
+ if (has_super) {
+ printf (_(" %s superblock at "),
+ i == 0 ? _("Primary") : _("Backup"));
+ print_number(super_blk);
+ }
+ if (old_desc_blk) {
+ printf("%s", _(", Group descriptors at "));
+ print_range(old_desc_blk,
+ old_desc_blk + old_desc_blocks - 1);
+ if (reserved_gdt) {
+ printf("%s", _("\n Reserved GDT blocks at "));
+ print_range(old_desc_blk + old_desc_blocks,
+ old_desc_blk + old_desc_blocks +
+ reserved_gdt - 1);
+ }
+ } else if (new_desc_blk) {
+ fputc(has_super ? ',' : ' ', stdout);
+ printf("%s", _(" Group descriptor at "));
+ print_number(new_desc_blk);
+ has_super++;
+ }
+ if (has_super)
+ fputc('\n', stdout);
+ fputs(_(" Block bitmap at "), stdout);
+ print_number(ext2fs_block_bitmap_loc(fs, i));
+ print_bg_rel_offset(fs, ext2fs_block_bitmap_loc(fs, i), 0,
+ first_block, last_block);
+ fputs(_(", Inode bitmap at "), stdout);
+ print_number(ext2fs_inode_bitmap_loc(fs, i));
+ print_bg_rel_offset(fs, ext2fs_inode_bitmap_loc(fs, i), 0,
+ first_block, last_block);
+ fputs(_("\n Inode table at "), stdout);
+ print_range(ext2fs_inode_table_loc(fs, i),
+ ext2fs_inode_table_loc(fs, i) +
+ inode_blocks_per_group - 1);
+ print_bg_rel_offset(fs, ext2fs_inode_table_loc(fs, i), 1,
+ first_block, last_block);
+ printf (_("\n %u free %s, %u free inodes, "
+ "%u directories%s"),
+ ext2fs_bg_free_blocks_count(fs, i), units,
+ ext2fs_bg_free_inodes_count(fs, i),
+ ext2fs_bg_used_dirs_count(fs, i),
+ ext2fs_bg_itable_unused(fs, i) ? "" : "\n");
+ if (ext2fs_bg_itable_unused(fs, i))
+ printf (_(", %u unused inodes\n"),
+ ext2fs_bg_itable_unused(fs, i));
+ if (block_bitmap) {
+ fputs(_(" Free blocks: "), stdout);
+ retval = ext2fs_get_block_bitmap_range2(fs->block_map,
+ blk_itr, block_nbytes << 3, block_bitmap);
+ if (retval)
+ com_err("list_desc", retval,
+ "while reading block bitmap");
+ else
+ print_free(i, block_bitmap,
+ fs->super->s_clusters_per_group,
+ fs->super->s_first_data_block,
+ EXT2FS_CLUSTER_RATIO(fs));
+ fputc('\n', stdout);
+ blk_itr += fs->super->s_clusters_per_group;
+ }
+ if (inode_bitmap) {
+ fputs(_(" Free inodes: "), stdout);
+ retval = ext2fs_get_inode_bitmap_range2(fs->inode_map,
+ ino_itr, inode_nbytes << 3, inode_bitmap);
+ if (retval)
+ com_err("list_desc", retval,
+ "while reading inode bitmap");
+ else
+ print_free(i, inode_bitmap,
+ fs->super->s_inodes_per_group,
+ 1, 1);
+ fputc('\n', stdout);
+ ino_itr += fs->super->s_inodes_per_group;
+ }
+ }
+ if (block_bitmap)
+ free(block_bitmap);
+ if (inode_bitmap)
+ free(inode_bitmap);
+}
+
+static void list_bad_blocks(ext2_filsys fs, int dump)
+{
+ badblocks_list bb_list = 0;
+ badblocks_iterate bb_iter;
+ blk_t blk;
+ errcode_t retval;
+ const char *header, *fmt;
+
+ retval = ext2fs_read_bb_inode(fs, &bb_list);
+ if (retval) {
+ com_err("ext2fs_read_bb_inode", retval, 0);
+ return;
+ }
+ retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
+ if (retval) {
+ com_err("ext2fs_badblocks_list_iterate_begin", retval,
+ "%s", _("while printing bad block list"));
+ return;
+ }
+ if (dump) {
+ header = fmt = "%u\n";
+ } else {
+ header = _("Bad blocks: %u");
+ fmt = ", %u";
+ }
+ while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
+ printf(header ? header : fmt, blk);
+ header = 0;
+ }
+ ext2fs_badblocks_list_iterate_end(bb_iter);
+ if (!dump)
+ fputc('\n', stdout);
+ ext2fs_badblocks_list_free(bb_list);
+}
+
+static void print_inline_journal_information(ext2_filsys fs)
+{
+ journal_superblock_t *jsb;
+ struct ext2_inode inode;
+ ext2_file_t journal_file;
+ errcode_t retval;
+ ino_t ino = fs->super->s_journal_inum;
+ char buf[1024];
+ __u32 *mask_ptr, mask, m;
+ int i, j, size, printed = 0;
+
+ if (fs->flags & EXT2_FLAG_IMAGE_FILE)
+ return;
+ retval = ext2fs_read_inode(fs, ino, &inode);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while reading journal inode"));
+ exit(1);
+ }
+ retval = ext2fs_file_open2(fs, ino, &inode, 0, &journal_file);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while opening journal inode"));
+ exit(1);
+ }
+ retval = ext2fs_file_read(journal_file, buf, sizeof(buf), 0);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while reading journal super block"));
+ exit(1);
+ }
+ ext2fs_file_close(journal_file);
+ jsb = (journal_superblock_t *) buf;
+ if (be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) {
+ fprintf(stderr, "%s",
+ _("Journal superblock magic number invalid!\n"));
+ exit(1);
+ }
+ printf("%s", _("Journal features: "));
+ for (i=0, mask_ptr=&jsb->s_feature_compat; i <3; i++,mask_ptr++) {
+ mask = be32_to_cpu(*mask_ptr);
+ for (j=0,m=1; j < 32; j++, m<<=1) {
+ if (mask & m) {
+ printf(" %s", e2p_jrnl_feature2string(i, m));
+ printed++;
+ }
+ }
+ }
+ if (printed == 0)
+ printf(" (none)");
+ printf("\n");
+ fputs(_("Journal size: "), stdout);
+ if ((fs->super->s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
+ (inode.i_flags & EXT4_HUGE_FILE_FL))
+ size = inode.i_blocks / (fs->blocksize / 1024);
+ else
+ size = inode.i_blocks >> 1;
+ if (size < 8192)
+ printf("%uk\n", size);
+ else
+ printf("%uM\n", size >> 10);
+ printf(_("Journal length: %u\n"
+ "Journal sequence: 0x%08x\n"
+ "Journal start: %u\n"),
+ (unsigned int)ntohl(jsb->s_maxlen),
+ (unsigned int)ntohl(jsb->s_sequence),
+ (unsigned int)ntohl(jsb->s_start));
+ if (jsb->s_errno != 0)
+ printf(_("Journal errno: %d\n"),
+ (int) ntohl(jsb->s_errno));
+}
+
+static void print_journal_information(ext2_filsys fs)
+{
+ errcode_t retval;
+ char buf[1024];
+ char str[80];
+ unsigned int i;
+ journal_superblock_t *jsb;
+
+ /* Get the journal superblock */
+ if ((retval = io_channel_read_blk64(fs->io,
+ fs->super->s_first_data_block + 1,
+ -1024, buf))) {
+ com_err(program_name, retval, "%s",
+ _("while reading journal superblock"));
+ exit(1);
+ }
+ jsb = (journal_superblock_t *) buf;
+ if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
+ (jsb->s_header.h_blocktype !=
+ (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
+ com_err(program_name, 0, "%s",
+ _("Couldn't find journal superblock magic numbers"));
+ exit(1);
+ }
+
+ printf(_("\nJournal block size: %u\n"
+ "Journal length: %u\n"
+ "Journal first block: %u\n"
+ "Journal sequence: 0x%08x\n"
+ "Journal start: %u\n"
+ "Journal number of users: %u\n"),
+ (unsigned int)ntohl(jsb->s_blocksize), (unsigned int)ntohl(jsb->s_maxlen),
+ (unsigned int)ntohl(jsb->s_first), (unsigned int)ntohl(jsb->s_sequence),
+ (unsigned int)ntohl(jsb->s_start), (unsigned int)ntohl(jsb->s_nr_users));
+
+ for (i=0; i < ntohl(jsb->s_nr_users); i++) {
+ uuid_unparse(&jsb->s_users[i*16], str);
+ printf(i ? " %s\n"
+ : _("Journal users: %s\n"),
+ str);
+ }
+}
+
+static void parse_extended_opts(const char *opts, blk64_t *superblock,
+ int *blocksize)
+{
+ char *buf, *token, *next, *p, *arg, *badopt = 0;
+ int len;
+ int do_usage = 0;
+
+ len = strlen(opts);
+ buf = malloc(len+1);
+ if (!buf) {
+ fprintf(stderr, "%s",
+ _("Couldn't allocate memory to parse options!\n"));
+ exit(1);
+ }
+ strcpy(buf, opts);
+ for (token = buf; token && *token; token = next) {
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+ arg = strchr(token, '=');
+ if (arg) {
+ *arg = 0;
+ arg++;
+ }
+ if (strcmp(token, "superblock") == 0 ||
+ strcmp(token, "sb") == 0) {
+ if (!arg) {
+ do_usage++;
+ badopt = token;
+ continue;
+ }
+ *superblock = strtoul(arg, &p, 0);
+ if (*p) {
+ fprintf(stderr,
+ _("Invalid superblock parameter: %s\n"),
+ arg);
+ do_usage++;
+ continue;
+ }
+ } else if (strcmp(token, "blocksize") == 0 ||
+ strcmp(token, "bs") == 0) {
+ if (!arg) {
+ do_usage++;
+ badopt = token;
+ continue;
+ }
+ *blocksize = strtoul(arg, &p, 0);
+ if (*p) {
+ fprintf(stderr,
+ _("Invalid blocksize parameter: %s\n"),
+ arg);
+ do_usage++;
+ continue;
+ }
+ } else {
+ do_usage++;
+ badopt = token;
+ }
+ }
+ if (do_usage) {
+ fprintf(stderr, _("\nBad extended option(s) specified: %s\n\n"
+ "Extended options are separated by commas, "
+ "and may take an argument which\n"
+ "\tis set off by an equals ('=') sign.\n\n"
+ "Valid extended options are:\n"
+ "\tsuperblock=<superblock number>\n"
+ "\tblocksize=<blocksize>\n"),
+ badopt ? badopt : "");
+ free(buf);
+ exit(1);
+ }
+ free(buf);
+}
+
+int main (int argc, char ** argv)
+{
+ errcode_t retval;
+ ext2_filsys fs;
+ int print_badblocks = 0;
+ blk64_t use_superblock = 0;
+ int use_blocksize = 0;
+ int image_dump = 0;
+ int force = 0;
+ int flags;
+ int header_only = 0;
+ int c;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+ add_error_table(&et_ext2_error_table);
+ fprintf (stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION,
+ E2FSPROGS_DATE);
+ if (argc && *argv)
+ program_name = *argv;
+
+ while ((c = getopt (argc, argv, "bfhixVo:")) != EOF) {
+ switch (c) {
+ case 'b':
+ print_badblocks++;
+ break;
+ case 'f':
+ force++;
+ break;
+ case 'h':
+ header_only++;
+ break;
+ case 'i':
+ image_dump++;
+ break;
+ case 'o':
+ parse_extended_opts(optarg, &use_superblock,
+ &use_blocksize);
+ break;
+ case 'V':
+ /* Print version number and exit */
+ fprintf(stderr, _("\tUsing %s\n"),
+ error_message(EXT2_ET_BASE));
+ exit(0);
+ case 'x':
+ hex_format++;
+ break;
+ default:
+ usage();
+ }
+ }
+ if (optind > argc - 1)
+ usage();
+ device_name = argv[optind++];
+ flags = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS;
+ if (force)
+ flags |= EXT2_FLAG_FORCE;
+ if (image_dump)
+ flags |= EXT2_FLAG_IMAGE_FILE;
+
+ if (use_superblock && !use_blocksize) {
+ for (use_blocksize = EXT2_MIN_BLOCK_SIZE;
+ use_blocksize <= EXT2_MAX_BLOCK_SIZE;
+ use_blocksize *= 2) {
+ retval = ext2fs_open (device_name, flags,
+ use_superblock,
+ use_blocksize, unix_io_manager,
+ &fs);
+ if (!retval)
+ break;
+ }
+ } else
+ retval = ext2fs_open (device_name, flags, use_superblock,
+ use_blocksize, unix_io_manager, &fs);
+ if (retval) {
+ com_err (program_name, retval, _("while trying to open %s"),
+ device_name);
+ printf("%s", _("Couldn't find valid filesystem superblock.\n"));
+ exit (1);
+ }
+ fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
+ if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
+ blocks64 = 1;
+ if (print_badblocks) {
+ list_bad_blocks(fs, 1);
+ } else {
+ list_super (fs->super);
+ if (fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+ print_journal_information(fs);
+ ext2fs_close(fs);
+ exit(0);
+ }
+ if ((fs->super->s_feature_compat &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+ (fs->super->s_journal_inum != 0))
+ print_inline_journal_information(fs);
+ list_bad_blocks(fs, 0);
+ if (header_only) {
+ ext2fs_close (fs);
+ exit (0);
+ }
+ retval = ext2fs_read_bitmaps (fs);
+ list_desc (fs);
+ if (retval) {
+ printf(_("\n%s: %s: error reading bitmaps: %s\n"),
+ program_name, device_name,
+ error_message(retval));
+ }
+ }
+ ext2fs_close (fs);
+ remove_error_table(&et_ext2_error_table);
+ exit (0);
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2freefrag.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2freefrag.8.in
new file mode 100644
index 0000000..564be74
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2freefrag.8.in
@@ -0,0 +1,96 @@
+.\" -*- nroff -*-
+.TH E2FREEFRAG 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+e2freefrag \- report free space fragmentation information
+.SH SYNOPSIS
+.B e2freefrag
+[
+.B \-c chunk_kb
+]
+[
+.B \-h
+]
+.B filesys
+
+.SH DESCRIPTION
+.B e2freefrag
+is used to report free space fragmentation on ext2/3/4 file systems.
+.I filesys
+is the filesystem device name (e.g.
+.IR /dev/hdc1 ", " /dev/md0 ).
+The
+.B e2freefrag
+program will scan the block bitmap information to check how many free blocks
+are present as contiguous and aligned free space. The percentage of contiguous
+free blocks of size and of alignment
+.IR chunk_kb
+is reported. It also displays the minimum/maximum/average free chunk size in
+the filesystem, along with a histogram of all free chunks. This information
+can be used to gauge the level of free space fragmentation in the filesystem.
+.SH OPTIONS
+.TP
+.BI \-c " chunk_kb"
+If a chunk size is specified, then
+.B e2freefrag
+will print how many free chunks of size
+.I chunk_kb
+are available in units of kilobytes (Kb). The chunk size must be a
+power of two and be larger than filesystem block size.
+.TP
+.BI \-h
+Print the usage of the program.
+.SH EXAMPLE
+# e2freefrag /dev/vgroot/lvhome
+.br
+Device: /dev/vgroot/lvhome
+.br
+Blocksize: 4096 bytes
+.br
+Total blocks: 1504085
+.br
+Free blocks: 292995 (19.5%)
+.br
+
+Min. free extent: 4 KB
+.br
+Max. free extent: 24008 KB
+.br
+Avg. free extent: 252 KB
+.br
+
+HISTOGRAM OF FREE EXTENT SIZES:
+.br
+Extent Size Range : Free extents Free Blocks Percent
+.br
+ 4K... 8K- : 704 704 0.2%
+.br
+ 8K... 16K- : 810 1979 0.7%
+.br
+ 16K... 32K- : 843 4467 1.5%
+.br
+ 32K... 64K- : 579 6263 2.1%
+.br
+ 64K... 128K- : 493 11067 3.8%
+.br
+ 128K... 256K- : 394 18097 6.2%
+.br
+ 256K... 512K- : 281 25477 8.7%
+.br
+ 512K... 1024K- : 253 44914 15.3%
+.br
+ 1M... 2M- : 143 51897 17.7%
+.br
+ 2M... 4M- : 73 50683 17.3%
+.br
+ 4M... 8M- : 37 52417 17.9%
+.br
+ 8M... 16M- : 7 19028 6.5%
+.br
+ 16M... 32M- : 1 6002 2.0%
+.SH AUTHOR
+This version of e2freefrag was written by Rupesh Thakare, and modified by
+Andreas Dilger <adilger@sun.com>, and Kalpak Shah.
+.SH SEE ALSO
+.IR debugfs (8),
+.IR dumpe2fs (8),
+.IR e2fsck (8)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2freefrag.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2freefrag.c
new file mode 100644
index 0000000..612ca44
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2freefrag.c
@@ -0,0 +1,336 @@
+/*
+ * e2freefrag - report filesystem free-space fragmentation
+ *
+ * Copyright (C) 2009 Sun Microsystems, Inc.
+ *
+ * Author: Rupesh Thakare <rupesh@sun.com>
+ * Andreas Dilger <adilger@sun.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License version 2.
+ * %End-Header%
+ */
+#include "config.h"
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+#include "e2freefrag.h"
+
+static void usage(const char *prog)
+{
+ fprintf(stderr, "usage: %s [-c chunksize in kb] [-h] "
+ "device_name\n", prog);
+#ifndef DEBUGFS
+ exit(1);
+#endif
+}
+
+static int ul_log2(unsigned long arg)
+{
+ int l = 0;
+
+ arg >>= 1;
+ while (arg) {
+ l++;
+ arg >>= 1;
+ }
+ return l;
+}
+
+static void init_chunk_info(ext2_filsys fs, struct chunk_info *info)
+{
+ int i;
+
+ info->blocksize_bits = ul_log2((unsigned long)fs->blocksize);
+ if (info->chunkbytes) {
+ info->chunkbits = ul_log2(info->chunkbytes);
+ info->blks_in_chunk = info->chunkbytes >> info->blocksize_bits;
+ } else {
+ info->chunkbits = ul_log2(DEFAULT_CHUNKSIZE);
+ info->blks_in_chunk = DEFAULT_CHUNKSIZE >> info->blocksize_bits;
+ }
+
+ info->min = ~0UL;
+ info->max = info->avg = 0;
+ info->real_free_chunks = 0;
+
+ for (i = 0; i < MAX_HIST; i++) {
+ info->histogram.fc_chunks[i] = 0;
+ info->histogram.fc_blocks[i] = 0;
+ }
+}
+
+static void update_chunk_stats(struct chunk_info *info,
+ unsigned long chunk_size)
+{
+ unsigned long idx;
+
+ idx = ul_log2(chunk_size) + 1;
+ if (idx >= MAX_HIST)
+ idx = MAX_HIST-1;
+ info->histogram.fc_chunks[idx]++;
+ info->histogram.fc_blocks[idx] += chunk_size;
+
+ if (chunk_size > info->max)
+ info->max = chunk_size;
+ if (chunk_size < info->min)
+ info->min = chunk_size;
+ info->avg += chunk_size;
+ info->real_free_chunks++;
+}
+
+static void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
+{
+ unsigned long long blocks_count = ext2fs_blocks_count(fs->super);
+ unsigned long long chunks = (blocks_count + info->blks_in_chunk) >>
+ (info->chunkbits - info->blocksize_bits);
+ unsigned long long chunk_num;
+ unsigned long last_chunk_size = 0;
+ unsigned long long chunk_start_blk = 0;
+ int used;
+
+ for (chunk_num = 0; chunk_num < chunks; chunk_num++) {
+ unsigned long long blk, num_blks;
+ int chunk_free;
+
+ /* Last chunk may be smaller */
+ if (chunk_start_blk + info->blks_in_chunk > blocks_count)
+ num_blks = blocks_count - chunk_start_blk;
+ else
+ num_blks = info->blks_in_chunk;
+
+ chunk_free = 0;
+
+ /* Initialize starting block for first chunk correctly else
+ * there is a segfault when blocksize = 1024 in which case
+ * block_map->start = 1 */
+ for (blk = 0; blk < num_blks; blk++, chunk_start_blk++) {
+ if (chunk_num == 0 && blk == 0) {
+ blk = fs->super->s_first_data_block;
+ chunk_start_blk = blk;
+ }
+ used = ext2fs_fast_test_block_bitmap2(fs->block_map,
+ chunk_start_blk >> fs->cluster_ratio_bits);
+ if (!used) {
+ last_chunk_size++;
+ chunk_free++;
+ }
+
+ if (used && last_chunk_size != 0) {
+ update_chunk_stats(info, last_chunk_size);
+ last_chunk_size = 0;
+ }
+ }
+
+ if (chunk_free == info->blks_in_chunk)
+ info->free_chunks++;
+ }
+ if (last_chunk_size != 0)
+ update_chunk_stats(info, last_chunk_size);
+}
+
+static errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info,
+ FILE *f)
+{
+ unsigned long total_chunks;
+ const char *unitp = "KMGTPEZY";
+ int units = 10;
+ unsigned long start = 0, end;
+ int i, retval = 0;
+
+ scan_block_bitmap(fs, info);
+
+ fprintf(f, "Total blocks: %llu\nFree blocks: %u (%0.1f%%)\n",
+ ext2fs_blocks_count(fs->super), fs->super->s_free_blocks_count,
+ (double)fs->super->s_free_blocks_count * 100 /
+ ext2fs_blocks_count(fs->super));
+
+ if (info->chunkbytes) {
+ fprintf(f, "\nChunksize: %lu bytes (%u blocks)\n",
+ info->chunkbytes, info->blks_in_chunk);
+ total_chunks = (ext2fs_blocks_count(fs->super) +
+ info->blks_in_chunk) >>
+ (info->chunkbits - info->blocksize_bits);
+ fprintf(f, "Total chunks: %lu\nFree chunks: %lu (%0.1f%%)\n",
+ total_chunks, info->free_chunks,
+ (double)info->free_chunks * 100 / total_chunks);
+ }
+
+ /* Display chunk information in KB */
+ if (info->real_free_chunks) {
+ unsigned int scale = fs->blocksize >> 10;
+ info->min = info->min * scale;
+ info->max = info->max * scale;
+ info->avg = info->avg / info->real_free_chunks * scale;
+ } else {
+ info->min = 0;
+ }
+
+ fprintf(f, "\nMin. free extent: %lu KB \nMax. free extent: %lu KB\n"
+ "Avg. free extent: %lu KB\n", info->min, info->max, info->avg);
+ fprintf(f, "Num. free extent: %lu\n", info->real_free_chunks);
+
+ fprintf(f, "\nHISTOGRAM OF FREE EXTENT SIZES:\n");
+ fprintf(f, "%s : %12s %12s %7s\n", "Extent Size Range",
+ "Free extents", "Free Blocks", "Percent");
+ for (i = 0; i < MAX_HIST; i++) {
+ end = 1 << (i + info->blocksize_bits - units);
+ if (info->histogram.fc_chunks[i] != 0) {
+ char end_str[32];
+
+ sprintf(end_str, "%5lu%c-", end, *unitp);
+ if (i == MAX_HIST-1)
+ strcpy(end_str, "max ");
+ fprintf(f, "%5lu%c...%7s : %12lu %12lu %6.2f%%\n",
+ start, *unitp, end_str,
+ info->histogram.fc_chunks[i],
+ info->histogram.fc_blocks[i],
+ (double)info->histogram.fc_blocks[i] * 100 /
+ fs->super->s_free_blocks_count);
+ }
+ start = end;
+ if (start == 1<<10) {
+ start = 1;
+ units += 10;
+ unitp++;
+ }
+ }
+
+ return retval;
+}
+
+static void close_device(char *device_name, ext2_filsys fs)
+{
+ int retval = ext2fs_close(fs);
+
+ if (retval)
+ com_err(device_name, retval, "while closing the filesystem.\n");
+}
+
+static void collect_info(ext2_filsys fs, struct chunk_info *chunk_info, FILE *f)
+{
+ unsigned int retval = 0;
+
+ fprintf(f, "Device: %s\n", fs->device_name);
+ fprintf(f, "Blocksize: %u bytes\n", fs->blocksize);
+
+ retval = ext2fs_read_block_bitmap(fs);
+ if (retval) {
+ com_err(fs->device_name, retval, "while reading block bitmap");
+ close_device(fs->device_name, fs);
+ exit(1);
+ }
+
+ init_chunk_info(fs, chunk_info);
+
+ retval = get_chunk_info(fs, chunk_info, f);
+ if (retval) {
+ com_err(fs->device_name, retval, "while collecting chunk info");
+ close_device(fs->device_name, fs);
+ exit(1);
+ }
+}
+
+#ifndef DEBUGFS
+static void open_device(char *device_name, ext2_filsys *fs)
+{
+ int retval;
+ int flag = EXT2_FLAG_FORCE | EXT2_FLAG_64BITS;
+
+ retval = ext2fs_open(device_name, flag, 0, 0, unix_io_manager, fs);
+ if (retval) {
+ com_err(device_name, retval, "while opening filesystem");
+ exit(1);
+ }
+ (*fs)->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
+}
+#endif
+
+#ifdef DEBUGFS
+#include "debugfs.h"
+
+void do_freefrag(int argc, char **argv)
+#else
+int main(int argc, char *argv[])
+#endif
+{
+ struct chunk_info chunk_info;
+ ext2_filsys fs = NULL;
+ char *progname;
+ char *end;
+ int c;
+
+#ifdef DEBUGFS
+ if (check_fs_open(argv[0]))
+ return;
+#else
+ char *device_name;
+
+ add_error_table(&et_ext2_error_table);
+#endif
+ progname = argv[0];
+ memset(&chunk_info, 0, sizeof(chunk_info));
+
+ while ((c = getopt(argc, argv, "c:h")) != EOF) {
+ switch (c) {
+ case 'c':
+ chunk_info.chunkbytes = strtoull(optarg, &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr, "%s: bad chunk size '%s'\n",
+ progname, optarg);
+ usage(progname);
+ }
+ if (chunk_info.chunkbytes &
+ (chunk_info.chunkbytes - 1)) {
+ fprintf(stderr, "%s: chunk size must be a "
+ "power of 2.\n", argv[0]);
+ usage(progname);
+ }
+ chunk_info.chunkbytes *= 1024;
+ break;
+ case 'h':
+ default:
+ usage(progname);
+ break;
+ }
+ }
+
+#ifndef DEBUGFS
+ if (optind == argc) {
+ fprintf(stderr, "%s: missing device name.\n", progname);
+ usage(progname);
+ }
+
+ device_name = argv[optind];
+
+ open_device(device_name, &fs);
+#else
+ fs = current_fs;
+#endif
+
+ if (chunk_info.chunkbytes && (chunk_info.chunkbytes < fs->blocksize)) {
+ fprintf(stderr, "%s: chunksize must be greater than or equal "
+ "to filesystem blocksize.\n", progname);
+ exit(1);
+ }
+ collect_info(fs, &chunk_info, stdout);
+#ifndef DEBUGFS
+ close_device(device_name, fs);
+
+ return 0;
+#endif
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2freefrag.h b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2freefrag.h
new file mode 100644
index 0000000..80d1eef
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2freefrag.h
@@ -0,0 +1,20 @@
+#include <sys/types.h>
+
+#define DEFAULT_CHUNKSIZE (1024*1024)
+
+#define MAX_HIST 32
+struct free_chunk_histogram {
+ unsigned long fc_chunks[MAX_HIST];
+ unsigned long fc_blocks[MAX_HIST];
+};
+
+struct chunk_info {
+ unsigned long chunkbytes; /* chunk size in bytes */
+ int chunkbits; /* chunk size in bits */
+ unsigned long free_chunks; /* total free chunks of given size */
+ unsigned long real_free_chunks; /* free chunks of any size */
+ int blocksize_bits; /* fs blocksize in bits */
+ int blks_in_chunk; /* number of blocks in a chunk */
+ unsigned long min, max, avg; /* chunk size stats */
+ struct free_chunk_histogram histogram; /* histogram of all chunk sizes*/
+};
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2image.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2image.8.in
new file mode 100644
index 0000000..75002d7
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2image.8.in
@@ -0,0 +1,285 @@
+.\" -*- nroff -*-
+.\" Copyright 2001 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH E2IMAGE 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+e2image \- Save critical ext2/ext3/ext4 filesystem metadata to a file
+.SH SYNOPSIS
+.B e2image
+[
+.B \-r|Q
+]
+[
+.B \-fr
+]
+.I device
+.I image-file
+.br
+.B e2image
+.B \-I
+.I device
+.I image-file
+.br
+.B e2image
+.B \-ra
+[
+.B \-cfnp
+]
+[
+.B \-o
+.I src_offset
+]
+[
+.B \-O
+.I dest_offset
+]
+.I src_fs
+[
+.I dest_fs
+]
+.SH DESCRIPTION
+The
+.B e2image
+program will save critical ext2, ext3, or ext4 filesystem metadata located on
+.I device
+to a file specified by
+.IR image-file .
+The image file may be examined by
+.B dumpe2fs
+and
+.BR debugfs ,
+by using the
+.B \-i
+option to those programs. This can assist an expert in
+recovering catastrophically corrupted filesystems. In the future,
+e2fsck will be enhanced to be able to use the image file to help
+recover a badly damaged filesystem.
+.PP
+When saving an e2image for debugging purposes, using either the
+.B \-r
+or
+.B \-Q
+options, the filesystem must be unmounted or be mounted read/only, in order
+for the image file to be in a consistent state. This requirement can be
+overriden using the
+.B \-f
+option, but the resulting image file is very likely not going to be useful.
+.PP
+If
+.I image-file
+is \-, then the output of
+.B e2image
+will be sent to standard output, so that the output can be piped to
+another program, such as
+.BR gzip (1).
+(Note that this is currently only supported when
+creating a raw image file using the
+.B \-r
+option, since the process of creating a normal image file, or QCOW2
+image currently
+requires random access to the file, which cannot be done using a
+pipe. This restriction will hopefully be lifted in a future version of
+.BR e2image .)
+.PP
+It is a very good idea to create image files for all of
+filesystems on a system and save the partition
+layout (which can be generated using the
+.B fdisk \-l
+command) at regular intervals --- at boot time, and/or every week or so.
+The image file should be stored on some filesystem other than
+the filesystem whose data it contains, to ensure that this data is
+accessible in the case where the filesystem has been badly damaged.
+.PP
+To save disk space,
+.B e2image
+creates the image file as a sparse file, or in QCOW2 format.
+Hence, if the sparse image file
+needs to be copied to another location, it should
+either be compressed first or copied using the
+.B \-\-sparse=always
+option to the GNU version of
+.BR cp .
+This does not apply to the QCOW2 image, which is not sparse.
+.PP
+The size of an ext2 image file depends primarily on the size of the
+filesystems and how many inodes are in use. For a typical 10 gigabyte
+filesystem, with 200,000 inodes in use out of 1.2 million inodes, the
+image file will be approximately 35 megabytes; a 4 gigabyte filesystem with
+15,000 inodes in use out of 550,000 inodes will result in a 3 megabyte
+image file. Image files tend to be quite
+compressible; an image file taking up 32 megabytes of space on
+disk will generally compress down to 3 or 4 megabytes.
+.PP
+.SH RESTORING FILESYSTEM METADATA USING AN IMAGE FILE
+.PP
+The
+.B \-I
+option will cause e2image to install the metadata stored in the image
+file back to the device. It can be used to restore the filesystem metadata
+back to the device in emergency situations.
+.PP
+.B WARNING!!!!
+The
+.B \-I
+option should only be used as a desperation measure when other
+alternatives have failed. If the filesystem has changed since the image
+file was created, data
+.B will
+be lost. In general, you should make a full image
+backup of the filesystem first, in case you wish to try other recovery
+strategies afterwards.
+.PP
+.SH RAW IMAGE FILES
+The
+.B \-r
+option will create a raw image file instead of a normal image file.
+A raw image file differs
+from a normal image file in two ways. First, the filesystem metadata is
+placed in the proper position so that e2fsck, dumpe2fs, debugfs,
+etc.\& can be run directly on the raw image file. In order to minimize
+the amount of disk space consumed by a raw image file, the file is
+created as a sparse file. (Beware of copying or
+compressing/decompressing this file with utilities that don't understand
+how to create sparse files; the file will become as large as the
+filesystem itself!) Secondly, the raw image file also includes indirect
+blocks and directory blocks, which the standard image file does not have,
+although this may change in the future.
+.PP
+Raw image files are sometimes used when sending filesystems to the maintainer
+as part of bug reports to e2fsprogs. When used in this capacity, the
+recommended command is as follows (replace hda1 with the appropriate device):
+.PP
+.br
+ \fBe2image \-r /dev/hda1 \- | bzip2 > hda1.e2i.bz2\fR
+.PP
+This will only send the metadata information, without any data blocks.
+However, the filenames in the directory blocks can still reveal
+information about the contents of the filesystem that the bug reporter
+may wish to keep confidential. To address this concern, the
+.B \-s
+option can be specified. This will cause
+.B e2image
+to scramble directory entries and zero out any unused portions
+of the directory blocks before writing the image file. However,
+the
+.B \-s
+option will prevent analysis of problems related to hash-tree indexed
+directories.
+.PP
+Note that this will work even if you substitute "/dev/hda1" for another raw
+disk image, or QCOW2 image previously created by
+.BR e2image .
+.PP
+.SH QCOW2 IMAGE FILES
+The
+.B \-Q
+option will create a QCOW2 image file instead of a normal, or raw image file.
+A QCOW2 image contains all the information the raw image does, however unlike
+the raw image it is not sparse. The QCOW2 image minimize the amount of disk
+space by storing data in special format with pack data closely together, hence
+avoiding holes while still minimizing size.
+.PP
+In order to send filesystem to the maintainer as a part of bug report to
+e2fsprogs, use following commands (replace hda1 with the appropriate device):
+.PP
+.br
+\ \fBe2image \-Q /dev/hda1 hda1.qcow2\fR
+.br
+\ \fBbzip2 -z hda1.qcow2\fR
+.PP
+This will only send the metadata information, without any data blocks.
+However, the filenames in the directory blocks can still reveal
+information about the contents of the filesystem that the bug reporter
+may wish to keep confidential. To address this concern, the
+.B \-s
+option can be specified. This will cause
+.B e2image
+to scramble directory entries and zero out any unused portions
+of the directory blocks before writing the image file. However, the
+.B \-s
+option will prevent analysis of problems related to hash-tree indexed
+directories.
+.PP
+Note that QCOW2 image created by
+.B e2image
+is regular QCOW2 image and can be processed by tools aware of QCOW2 format
+such as for example
+.BR qemu-img .
+.PP
+You can convert a qcow2 image into a raw image with:
+.PP
+.br
+\ \fBe2image \-r hda1.qcow2 hda1.raw\fR
+.br
+.PP
+This can be useful to write a qcow2 image containing all data to a
+sparse image file where it can be loop mounted, or to a disk partition.
+Note that this may not work with qcow2 images not generated by e2image.
+.PP
+.SH INCLUDING DATA
+Normally
+.B e2image
+only includes fs metadata, not regular file data. The
+.B \-a
+option can be specified to include all data. This will
+give an image that is suitable to use to clone the entire FS or
+for backup purposes. Note that this option only works with the
+raw or QCOW2 formats. The
+.B \-p
+switch may be given to show progress. If the file system is being
+cloned to a flash-based storage device (where reads are very fast and
+where it is desirable to avoid unnecessary writes to reduce write wear
+on the device), the
+.B \-c
+option which cause e2image to try reading a block from the destination
+to see if it is identical to the block which
+.B e2image
+is about to copy. If the block is already the same, the write can be
+skipped. The
+.B \-n
+option will cause all of the writes to be no-ops, and print the blocks
+that would have been written.
+.PP
+.SH OFFSETS
+Normally a filesystem starts at the beginning of a partition, and
+.B e2image
+is run on the partition. When working with image files, you don't
+have the option of using the partition device, so you can specify
+the offset where the filesystem starts directly with the
+.B \-o
+option. Similarly the
+.B \-O
+option specifies the offset that should be seeked to in the destination
+before writing the filesystem.
+.PP
+For example, if you have a
+.B dd
+image of a whole hard drive that contains an ext2 fs in a partition
+starting at 1 MiB, you can clone that fs with:
+.PP
+.br
+\ \fBe2image \-aro 1048576 img /dev/sda1\fR
+.br
+.PP
+Or you can clone a fs into an image file, leaving room in the first
+MiB for a partition table with:
+.PP
+.br
+\ \fBe2image -arO 1048576 /dev/sda1 img\fR
+.br
+.PP
+If you specify at least one offset, and only one file, an in-place
+move will be performed, allowing you to safely move the filesystem
+from one offset to another.
+.SH AUTHOR
+.B e2image
+was written by Theodore Ts'o (tytso@mit.edu).
+.SH AVAILABILITY
+.B e2image
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR dumpe2fs (8),
+.BR debugfs (8)
+
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2image.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2image.c
new file mode 100644
index 0000000..0537b0d
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2image.c
@@ -0,0 +1,1663 @@
+/*
+ * e2image.c --- Program which writes an image file backing up
+ * critical metadata for the filesystem.
+ *
+ * Copyright 2000, 2001 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include "config.h"
+#include <fcntl.h>
+#include <grp.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+#include <pwd.h>
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <signal.h>
+
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+#include "et/com_err.h"
+#include "uuid/uuid.h"
+#include "e2p/e2p.h"
+#include "ext2fs/e2image.h"
+#include "ext2fs/qcow2.h"
+
+#include "../version.h"
+#include "nls-enable.h"
+
+#define QCOW_OFLAG_COPIED (1LL << 63)
+#define NO_BLK ((blk64_t) -1)
+
+/* Image types */
+#define E2IMAGE_RAW 1
+#define E2IMAGE_QCOW2 2
+
+/* Image flags */
+#define E2IMAGE_INSTALL_FLAG 1
+#define E2IMAGE_SCRAMBLE_FLAG 2
+#define E2IMAGE_IS_QCOW2_FLAG 4
+#define E2IMAGE_CHECK_ZERO_FLAG 8
+
+static const char * program_name = "e2image";
+static char * device_name = NULL;
+static char all_data;
+static char output_is_blk;
+static char nop_flag;
+/* writing to blk device: don't skip zeroed blocks */
+static blk64_t source_offset, dest_offset;
+static char move_mode;
+static char show_progress;
+static char *check_buf;
+static int skipped_blocks;
+
+static blk64_t align_offset(blk64_t offset, unsigned int n)
+{
+ return (offset + n - 1) & ~((blk64_t) n - 1);
+}
+
+static int get_bits_from_size(size_t size)
+{
+ int res = 0;
+
+ if (size == 0)
+ return -1;
+
+ while (size != 1) {
+ /* Not a power of two */
+ if (size & 1)
+ return -1;
+
+ size >>= 1;
+ res++;
+ }
+ return res;
+}
+
+static void usage(void)
+{
+ fprintf(stderr, _("Usage: %s [ -r|Q ] [ -fr ] device image-file\n"),
+ program_name);
+ fprintf(stderr, _(" %s -I device image-file\n"), program_name);
+ fprintf(stderr, _(" %s -ra [ -cfnp ] [ -o src_offset ] "
+ "[ -O dest_offset ] src_fs [ dest_fs ]\n"),
+ program_name);
+ exit (1);
+}
+
+static ext2_loff_t seek_relative(int fd, int offset)
+{
+ ext2_loff_t ret = ext2fs_llseek(fd, offset, SEEK_CUR);
+ if (ret < 0) {
+ perror("seek_relative");
+ exit(1);
+ }
+ return ret;
+}
+
+static ext2_loff_t seek_set(int fd, ext2_loff_t offset)
+{
+ ext2_loff_t ret = ext2fs_llseek(fd, offset, SEEK_SET);
+ if (ret < 0) {
+ perror("seek_set");
+ exit(1);
+ }
+ return ret;
+}
+
+/*
+ * Returns true if the block we are about to write is identical to
+ * what is already on the disk.
+ */
+static int check_block(int fd, void *buf, void *cbuf, int blocksize)
+{
+ char *cp = cbuf;
+ int count = blocksize, ret;
+
+ if (cbuf == NULL)
+ return 0;
+
+ while (count > 0) {
+ ret = read(fd, cp, count);
+ if (ret < 0) {
+ perror("check_block");
+ exit(1);
+ }
+ count -= ret;
+ cp += ret;
+ }
+ ret = memcmp(buf, cbuf, blocksize);
+ seek_relative(fd, -blocksize);
+ return (ret == 0) ? 1 : 0;
+}
+
+static void generic_write(int fd, void *buf, int blocksize, blk64_t block)
+{
+ int count, free_buf = 0;
+ errcode_t err;
+
+ if (!blocksize)
+ return;
+
+ if (!buf) {
+ free_buf = 1;
+ err = ext2fs_get_arrayzero(1, blocksize, &buf);
+ if (err) {
+ com_err(program_name, err,
+ _("while allocating buffer"));
+ exit(1);
+ }
+ }
+ if (nop_flag) {
+ printf(_("Writing block %llu\n"), (unsigned long long) block);
+ if (fd != 1)
+ seek_relative(fd, blocksize);
+ return;
+ }
+ count = write(fd, buf, blocksize);
+ if (count != blocksize) {
+ if (count == -1)
+ err = errno;
+ else
+ err = 0;
+
+ if (block)
+ com_err(program_name, err,
+ _("error writing block %llu"), block);
+ else
+ com_err(program_name, err, _("error in write()"));
+
+ exit(1);
+ }
+ if (free_buf)
+ ext2fs_free_mem(&buf);
+}
+
+static void write_header(int fd, void *hdr, int hdr_size, int wrt_size)
+{
+ char *header_buf;
+ int ret;
+
+ /* Sanity check */
+ if (hdr_size > wrt_size) {
+ fprintf(stderr, "%s",
+ _("Error: header size is bigger than wrt_size\n"));
+ }
+
+ ret = ext2fs_get_mem(wrt_size, &header_buf);
+ if (ret) {
+ fputs(_("Couldn't allocate header buffer\n"), stderr);
+ exit(1);
+ }
+
+ seek_set(fd, 0);
+ memset(header_buf, 0, wrt_size);
+
+ if (hdr)
+ memcpy(header_buf, hdr, hdr_size);
+
+ generic_write(fd, header_buf, wrt_size, NO_BLK);
+
+ ext2fs_free_mem(&header_buf);
+}
+
+static void write_image_file(ext2_filsys fs, int fd)
+{
+ struct ext2_image_hdr hdr;
+ struct stat st;
+ errcode_t retval;
+
+ write_header(fd, NULL, sizeof(struct ext2_image_hdr), fs->blocksize);
+ memset(&hdr, 0, sizeof(struct ext2_image_hdr));
+
+ hdr.offset_super = seek_relative(fd, 0);
+ retval = ext2fs_image_super_write(fs, fd, 0);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while writing superblock"));
+ exit(1);
+ }
+
+ hdr.offset_inode = seek_relative(fd, 0);
+ retval = ext2fs_image_inode_write(fs, fd,
+ (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while writing inode table"));
+ exit(1);
+ }
+
+ hdr.offset_blockmap = seek_relative(fd, 0);
+ retval = ext2fs_image_bitmap_write(fs, fd, 0);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while writing block bitmap"));
+ exit(1);
+ }
+
+ hdr.offset_inodemap = seek_relative(fd, 0);
+ retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while writing inode bitmap"));
+ exit(1);
+ }
+
+ hdr.magic_number = EXT2_ET_MAGIC_E2IMAGE;
+ strcpy(hdr.magic_descriptor, "Ext2 Image 1.0");
+ gethostname(hdr.fs_hostname, sizeof(hdr.fs_hostname));
+ strncpy(hdr.fs_device_name, device_name, sizeof(hdr.fs_device_name)-1);
+ hdr.fs_device_name[sizeof(hdr.fs_device_name) - 1] = 0;
+ hdr.fs_blocksize = fs->blocksize;
+
+ if (stat(device_name, &st) == 0)
+ hdr.fs_device = st.st_rdev;
+
+ if (fstat(fd, &st) == 0) {
+ hdr.image_device = st.st_dev;
+ hdr.image_inode = st.st_ino;
+ }
+ memcpy(hdr.fs_uuid, fs->super->s_uuid, sizeof(hdr.fs_uuid));
+
+ hdr.image_time = time(0);
+ write_header(fd, &hdr, sizeof(struct ext2_image_hdr), fs->blocksize);
+}
+
+/*
+ * These set of functions are used to write a RAW image file.
+ */
+static ext2fs_block_bitmap meta_block_map;
+static ext2fs_block_bitmap scramble_block_map; /* Directory blocks to be scrambled */
+static blk64_t meta_blocks_count;
+
+struct process_block_struct {
+ ext2_ino_t ino;
+ int is_dir;
+};
+
+/*
+ * These subroutines short circuits ext2fs_get_blocks and
+ * ext2fs_check_directory; we use them since we already have the inode
+ * structure, so there's no point in letting the ext2fs library read
+ * the inode again.
+ */
+static ino_t stashed_ino = 0;
+static struct ext2_inode *stashed_inode;
+
+static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)),
+ ext2_ino_t ino,
+ blk_t *blocks)
+{
+ int i;
+
+ if ((ino != stashed_ino) || !stashed_inode)
+ return EXT2_ET_CALLBACK_NOTHANDLED;
+
+ for (i=0; i < EXT2_N_BLOCKS; i++)
+ blocks[i] = stashed_inode->i_block[i];
+ return 0;
+}
+
+static errcode_t meta_check_directory(ext2_filsys fs EXT2FS_ATTR((unused)),
+ ext2_ino_t ino)
+{
+ if ((ino != stashed_ino) || !stashed_inode)
+ return EXT2_ET_CALLBACK_NOTHANDLED;
+
+ if (!LINUX_S_ISDIR(stashed_inode->i_mode))
+ return EXT2_ET_NO_DIRECTORY;
+ return 0;
+}
+
+static errcode_t meta_read_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
+ ext2_ino_t ino,
+ struct ext2_inode *inode)
+{
+ if ((ino != stashed_ino) || !stashed_inode)
+ return EXT2_ET_CALLBACK_NOTHANDLED;
+ *inode = *stashed_inode;
+ return 0;
+}
+
+static void use_inode_shortcuts(ext2_filsys fs, int use_shortcuts)
+{
+ if (use_shortcuts) {
+ fs->get_blocks = meta_get_blocks;
+ fs->check_directory = meta_check_directory;
+ fs->read_inode = meta_read_inode;
+ stashed_ino = 0;
+ } else {
+ fs->get_blocks = 0;
+ fs->check_directory = 0;
+ fs->read_inode = 0;
+ }
+}
+
+static int process_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)),
+ blk64_t *block_nr,
+ e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
+ blk64_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data EXT2FS_ATTR((unused)))
+{
+ struct process_block_struct *p;
+
+ p = (struct process_block_struct *) priv_data;
+
+ ext2fs_mark_block_bitmap2(meta_block_map, *block_nr);
+ meta_blocks_count++;
+ if (scramble_block_map && p->is_dir && blockcnt >= 0)
+ ext2fs_mark_block_bitmap2(scramble_block_map, *block_nr);
+ return 0;
+}
+
+static int process_file_block(ext2_filsys fs EXT2FS_ATTR((unused)),
+ blk64_t *block_nr,
+ e2_blkcnt_t blockcnt,
+ blk64_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data EXT2FS_ATTR((unused)))
+{
+ if (blockcnt < 0 || all_data) {
+ ext2fs_mark_block_bitmap2(meta_block_map, *block_nr);
+ meta_blocks_count++;
+ }
+ return 0;
+}
+
+static void mark_table_blocks(ext2_filsys fs)
+{
+ blk64_t first_block, b;
+ unsigned int i,j;
+
+ first_block = fs->super->s_first_data_block;
+ /*
+ * Mark primary superblock
+ */
+ ext2fs_mark_block_bitmap2(meta_block_map, first_block);
+ meta_blocks_count++;
+
+ /*
+ * Mark the primary superblock descriptors
+ */
+ for (j = 0; j < fs->desc_blocks; j++) {
+ ext2fs_mark_block_bitmap2(meta_block_map,
+ ext2fs_descriptor_block_loc2(fs, first_block, j));
+ }
+ meta_blocks_count += fs->desc_blocks;
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ /*
+ * Mark the blocks used for the inode table
+ */
+ if ((output_is_blk ||
+ !ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT)) &&
+ ext2fs_inode_table_loc(fs, i)) {
+ unsigned int end = (unsigned) fs->inode_blocks_per_group;
+ /* skip unused blocks */
+ if (!output_is_blk &&
+ EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+ end -= (ext2fs_bg_itable_unused(fs, i) /
+ EXT2_INODES_PER_BLOCK(fs->super));
+ for (j = 0, b = ext2fs_inode_table_loc(fs, i);
+ j < end;
+ j++, b++) {
+ ext2fs_mark_block_bitmap2(meta_block_map, b);
+ meta_blocks_count++;
+ }
+ }
+
+ /*
+ * Mark block used for the block bitmap
+ */
+ if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) &&
+ ext2fs_block_bitmap_loc(fs, i)) {
+ ext2fs_mark_block_bitmap2(meta_block_map,
+ ext2fs_block_bitmap_loc(fs, i));
+ meta_blocks_count++;
+ }
+
+ /*
+ * Mark block used for the inode bitmap
+ */
+ if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) &&
+ ext2fs_inode_bitmap_loc(fs, i)) {
+ ext2fs_mark_block_bitmap2(meta_block_map,
+ ext2fs_inode_bitmap_loc(fs, i));
+ meta_blocks_count++;
+ }
+ }
+}
+
+/*
+ * This function returns 1 if the specified block is all zeros
+ */
+static int check_zero_block(char *buf, int blocksize)
+{
+ char *cp = buf;
+ int left = blocksize;
+
+ if (output_is_blk)
+ return 0;
+ while (left > 0) {
+ if (*cp++)
+ return 0;
+ left--;
+ }
+ return 1;
+}
+
+static int name_id[256];
+
+#define EXT4_MAX_REC_LEN ((1<<16)-1)
+
+static void scramble_dir_block(ext2_filsys fs, blk64_t blk, char *buf)
+{
+ char *p, *end, *cp;
+ struct ext2_dir_entry_2 *dirent;
+ unsigned int rec_len;
+ int id, len;
+
+ end = buf + fs->blocksize;
+ for (p = buf; p < end-8; p += rec_len) {
+ dirent = (struct ext2_dir_entry_2 *) p;
+ rec_len = dirent->rec_len;
+#ifdef WORDS_BIGENDIAN
+ rec_len = ext2fs_swab16(rec_len);
+#endif
+ if (rec_len == EXT4_MAX_REC_LEN || rec_len == 0)
+ rec_len = fs->blocksize;
+ else
+ rec_len = (rec_len & 65532) | ((rec_len & 3) << 16);
+#if 0
+ printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len);
+#endif
+ if (rec_len < 8 || (rec_len % 4) ||
+ (p+rec_len > end)) {
+ printf(_("Corrupt directory block %llu: "
+ "bad rec_len (%d)\n"),
+ (unsigned long long) blk, rec_len);
+ rec_len = end - p;
+ (void) ext2fs_set_rec_len(fs, rec_len,
+ (struct ext2_dir_entry *) dirent);
+#ifdef WORDS_BIGENDIAN
+ dirent->rec_len = ext2fs_swab16(dirent->rec_len);
+#endif
+ continue;
+ }
+ if (dirent->name_len + 8U > rec_len) {
+ printf(_("Corrupt directory block %llu: "
+ "bad name_len (%d)\n"),
+ (unsigned long long) blk, dirent->name_len);
+ dirent->name_len = rec_len - 8;
+ continue;
+ }
+ cp = p+8;
+ len = rec_len - dirent->name_len - 8;
+ if (len > 0)
+ memset(cp+dirent->name_len, 0, len);
+ if (dirent->name_len==1 && cp[0] == '.')
+ continue;
+ if (dirent->name_len==2 && cp[0] == '.' && cp[1] == '.')
+ continue;
+
+ memset(cp, 'A', dirent->name_len);
+ len = dirent->name_len;
+ id = name_id[len]++;
+ while ((len > 0) && (id > 0)) {
+ *cp += id % 26;
+ id = id / 26;
+ cp++;
+ len--;
+ }
+ }
+}
+
+static char got_sigint;
+
+static void sigint_handler(int unused EXT2FS_ATTR((unused)))
+{
+ got_sigint = 1;
+ signal (SIGINT, SIG_DFL);
+}
+
+#define calc_percent(a, b) ((int) ((100.0 * (((float) (a)) / \
+ ((float) (b)))) + 0.5))
+#define calc_rate(t, b, d) (((float)(t) / ((1024 * 1024) / (b))) / (d))
+
+static int print_progress(blk64_t num, blk64_t total)
+{
+ return fprintf(stderr, _("%llu / %llu blocks (%d%%)"), num, total,
+ calc_percent(num, total));
+}
+
+static void output_meta_data_blocks(ext2_filsys fs, int fd, int flags)
+{
+ errcode_t retval;
+ blk64_t blk;
+ char *buf, *zero_buf;
+ int sparse = 0;
+ blk64_t start = 0;
+ blk64_t distance = 0;
+ blk64_t end = ext2fs_blocks_count(fs->super);
+ time_t last_update = 0;
+ time_t start_time = 0;
+ blk64_t total_written = 0;
+ int bscount = 0;
+
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval) {
+ com_err(program_name, retval, _("while allocating buffer"));
+ exit(1);
+ }
+ retval = ext2fs_get_memzero(fs->blocksize, &zero_buf);
+ if (retval) {
+ com_err(program_name, retval, _("while allocating buffer"));
+ exit(1);
+ }
+ if (show_progress) {
+ fprintf(stderr, _("Copying "));
+ bscount = print_progress(total_written, meta_blocks_count);
+ fflush(stderr);
+ last_update = time(NULL);
+ start_time = time(NULL);
+ }
+ /* when doing an in place move to the right, you can't start
+ at the beginning or you will overwrite data, so instead
+ divide the fs up into distance size chunks and write them
+ in reverse. */
+ if (move_mode && dest_offset > source_offset) {
+ distance = (dest_offset - source_offset) / fs->blocksize;
+ if (distance < ext2fs_blocks_count(fs->super))
+ start = ext2fs_blocks_count(fs->super) - distance;
+ }
+ if (move_mode)
+ signal (SIGINT, sigint_handler);
+more_blocks:
+ if (distance)
+ seek_set(fd, (start * fs->blocksize) + dest_offset);
+ for (blk = start; blk < end; blk++) {
+ if (got_sigint) {
+ if (distance) {
+ /* moving to the right */
+ if (distance >= ext2fs_blocks_count(fs->super) ||
+ start == ext2fs_blocks_count(fs->super) - distance)
+ kill (getpid(), SIGINT);
+ } else {
+ /* moving to the left */
+ if (blk < (source_offset - dest_offset) / fs->blocksize)
+ kill (getpid(), SIGINT);
+ }
+ if (show_progress)
+ fputc('\r', stderr);
+ fprintf(stderr,
+ _("Stopping now will destroy the filesystem, "
+ "interrupt again if you are sure\n"));
+ if (show_progress) {
+ fprintf(stderr, _("Copying "));
+ bscount = print_progress(total_written,
+ meta_blocks_count);
+ fflush(stderr);
+ }
+
+ got_sigint = 0;
+ }
+ if (show_progress && last_update != time(NULL)) {
+ time_t duration;
+ last_update = time(NULL);
+ while (bscount--)
+ fputc('\b', stderr);
+ bscount = print_progress(total_written,
+ meta_blocks_count);
+ duration = time(NULL) - start_time;
+ if (duration > 5) {
+ time_t est = (duration * meta_blocks_count /
+ total_written) - duration;
+ char buff[30];
+ strftime(buff, 30, "%T", gmtime(&est));
+ bscount += fprintf(stderr,
+ _(" %s remaining at %.2f MB/s"),
+ buff, calc_rate(total_written,
+ fs->blocksize,
+ duration));
+ }
+ fflush (stderr);
+ }
+ if ((blk >= fs->super->s_first_data_block) &&
+ ext2fs_test_block_bitmap2(meta_block_map, blk)) {
+ retval = io_channel_read_blk64(fs->io, blk, 1, buf);
+ if (retval) {
+ com_err(program_name, retval,
+ _("error reading block %llu"), blk);
+ }
+ total_written++;
+ if (scramble_block_map &&
+ ext2fs_test_block_bitmap2(scramble_block_map, blk))
+ scramble_dir_block(fs, blk, buf);
+ if ((flags & E2IMAGE_CHECK_ZERO_FLAG) &&
+ check_zero_block(buf, fs->blocksize))
+ goto sparse_write;
+ if (sparse)
+ seek_relative(fd, sparse);
+ sparse = 0;
+ if (check_block(fd, buf, check_buf, fs->blocksize)) {
+ seek_relative(fd, fs->blocksize);
+ skipped_blocks++;
+ } else
+ generic_write(fd, buf, fs->blocksize, blk);
+ } else {
+ sparse_write:
+ if (fd == 1) {
+ if (!nop_flag)
+ generic_write(fd, zero_buf,
+ fs->blocksize, blk);
+ continue;
+ }
+ sparse += fs->blocksize;
+ if (sparse > 1024*1024) {
+ seek_relative(fd, 1024*1024);
+ sparse -= 1024*1024;
+ }
+ }
+ }
+ if (distance && start) {
+ if (start < distance) {
+ end = start;
+ start = 0;
+ } else {
+ end -= distance;
+ start -= distance;
+ if (end < distance) {
+ /* past overlap, do rest in one go */
+ end = start;
+ start = 0;
+ }
+ }
+ sparse = 0;
+ goto more_blocks;
+ }
+ signal (SIGINT, SIG_DFL);
+ if (show_progress) {
+ time_t duration = time(NULL) - start_time;
+ char buff[30];
+ while (bscount--)
+ fputc('\b', stderr);
+ strftime(buff, 30, "%T", gmtime(&duration));
+ fprintf(stderr, _("\b\b\b\b\b\b\b\bCopied %llu / %llu "
+ "blocks (%llu%%) in %s at %.2f MB/s \n"),
+ total_written, meta_blocks_count,
+ calc_percent(total_written, meta_blocks_count), buff,
+ calc_rate(total_written, fs->blocksize, duration));
+ }
+#ifdef HAVE_FTRUNCATE64
+ if (sparse) {
+ ext2_loff_t offset;
+ if (distance)
+ offset = seek_set(fd,
+ fs->blocksize * ext2fs_blocks_count(fs->super) + dest_offset);
+ else
+ offset = seek_relative(fd, sparse);
+
+ if (ftruncate64(fd, offset) < 0) {
+ seek_relative(fd, -1);
+ generic_write(fd, zero_buf, 1, NO_BLK);
+ }
+ }
+#else
+ if (sparse && !distance) {
+ seek_relative(fd, sparse-1);
+ generic_write(fd, zero_buf, 1, NO_BLK);
+ }
+#endif
+ ext2fs_free_mem(&zero_buf);
+ ext2fs_free_mem(&buf);
+}
+
+static void init_l1_table(struct ext2_qcow2_image *image)
+{
+ __u64 *l1_table;
+ errcode_t ret;
+
+ ret = ext2fs_get_arrayzero(image->l1_size, sizeof(__u64), &l1_table);
+ if (ret) {
+ com_err(program_name, ret, _("while allocating l1 table"));
+ exit(1);
+ }
+
+ image->l1_table = l1_table;
+}
+
+static void init_l2_cache(struct ext2_qcow2_image *image)
+{
+ unsigned int count, i;
+ struct ext2_qcow2_l2_cache *cache;
+ struct ext2_qcow2_l2_table *table;
+ errcode_t ret;
+
+ ret = ext2fs_get_arrayzero(1, sizeof(struct ext2_qcow2_l2_cache),
+ &cache);
+ if (ret)
+ goto alloc_err;
+
+ count = (image->l1_size > L2_CACHE_PREALLOC) ? L2_CACHE_PREALLOC :
+ image->l1_size;
+
+ cache->count = count;
+ cache->free = count;
+ cache->next_offset = image->l2_offset;
+
+ for (i = 0; i < count; i++) {
+ ret = ext2fs_get_arrayzero(1,
+ sizeof(struct ext2_qcow2_l2_table), &table);
+ if (ret)
+ goto alloc_err;
+
+ ret = ext2fs_get_arrayzero(image->l2_size,
+ sizeof(__u64), &table->data);
+ if (ret)
+ goto alloc_err;
+
+ table->next = cache->free_head;
+ cache->free_head = table;
+ }
+
+ image->l2_cache = cache;
+ return;
+
+alloc_err:
+ com_err(program_name, ret, _("while allocating l2 cache"));
+ exit(1);
+}
+
+static void put_l2_cache(struct ext2_qcow2_image *image)
+{
+ struct ext2_qcow2_l2_cache *cache = image->l2_cache;
+ struct ext2_qcow2_l2_table *tmp, *table;
+
+ if (!cache)
+ return;
+
+ table = cache->free_head;
+ cache->free_head = NULL;
+again:
+ while (table) {
+ tmp = table;
+ table = table->next;
+ ext2fs_free_mem(&tmp->data);
+ ext2fs_free_mem(&tmp);
+ }
+
+ if (cache->free != cache->count) {
+ fprintf(stderr, _("Warning: There are still tables in the "
+ "cache while putting the cache, data will "
+ "be lost so the image may not be valid.\n"));
+ table = cache->used_head;
+ cache->used_head = NULL;
+ goto again;
+ }
+
+ ext2fs_free_mem(&cache);
+}
+
+static int init_refcount(struct ext2_qcow2_image *img, blk64_t table_offset)
+{
+ struct ext2_qcow2_refcount *ref;
+ blk64_t table_clusters;
+ errcode_t ret;
+
+ ref = &(img->refcount);
+
+ /*
+ * One refcount block addresses 2048 clusters, one refcount table
+ * addresses cluster/sizeof(__u64) refcount blocks, and we need
+ * to address meta_blocks_count clusters + qcow2 metadata clusters
+ * in the worst case.
+ */
+ table_clusters = meta_blocks_count + (table_offset >>
+ img->cluster_bits);
+ table_clusters >>= (img->cluster_bits + 6 - 1);
+ table_clusters = (table_clusters == 0) ? 1 : table_clusters;
+
+ ref->refcount_table_offset = table_offset;
+ ref->refcount_table_clusters = table_clusters;
+ ref->refcount_table_index = 0;
+ ref->refcount_block_index = 0;
+
+ /* Allocate refcount table */
+ ret = ext2fs_get_arrayzero(ref->refcount_table_clusters,
+ img->cluster_size, &ref->refcount_table);
+ if (ret)
+ return ret;
+
+ /* Allocate refcount block */
+ ret = ext2fs_get_arrayzero(1, img->cluster_size, &ref->refcount_block);
+ if (ret)
+ ext2fs_free_mem(&ref->refcount_table);
+
+ return ret;
+}
+
+static int initialize_qcow2_image(int fd, ext2_filsys fs,
+ struct ext2_qcow2_image *image)
+{
+ struct ext2_qcow2_hdr *header;
+ blk64_t total_size, offset;
+ int shift, l2_bits, header_size, l1_size, ret;
+ int cluster_bits = get_bits_from_size(fs->blocksize);
+ struct ext2_super_block *sb = fs->super;
+
+ /* Allocate header */
+ ret = ext2fs_get_memzero(sizeof(struct ext2_qcow2_hdr), &header);
+ if (ret)
+ return ret;
+
+ total_size = ext2fs_blocks_count(sb) << cluster_bits;
+ image->cluster_size = fs->blocksize;
+ image->l2_size = 1 << (cluster_bits - 3);
+ image->cluster_bits = cluster_bits;
+ image->fd = fd;
+
+ header->magic = ext2fs_cpu_to_be32(QCOW_MAGIC);
+ header->version = ext2fs_cpu_to_be32(QCOW_VERSION);
+ header->size = ext2fs_cpu_to_be64(total_size);
+ header->cluster_bits = ext2fs_cpu_to_be32(cluster_bits);
+
+ header_size = (sizeof(struct ext2_qcow2_hdr) + 7) & ~7;
+ offset = align_offset(header_size, image->cluster_size);
+
+ header->l1_table_offset = ext2fs_cpu_to_be64(offset);
+ image->l1_offset = offset;
+
+ l2_bits = cluster_bits - 3;
+ shift = cluster_bits + l2_bits;
+ l1_size = ((total_size + (1LL << shift) - 1) >> shift);
+ header->l1_size = ext2fs_cpu_to_be32(l1_size);
+ image->l1_size = l1_size;
+
+ /* Make space for L1 table */
+ offset += align_offset(l1_size * sizeof(blk64_t), image->cluster_size);
+
+ /* Initialize refcounting */
+ ret = init_refcount(image, offset);
+ if (ret) {
+ ext2fs_free_mem(&header);
+ return ret;
+ }
+ header->refcount_table_offset = ext2fs_cpu_to_be64(offset);
+ header->refcount_table_clusters =
+ ext2fs_cpu_to_be32(image->refcount.refcount_table_clusters);
+ offset += image->cluster_size;
+ offset += image->refcount.refcount_table_clusters <<
+ image->cluster_bits;
+
+ /* Make space for L2 tables */
+ image->l2_offset = offset;
+ offset += image->cluster_size;
+
+ /* Make space for first refcount block */
+ image->refcount.refcount_block_offset = offset;
+
+ image->hdr = header;
+ /* Initialize l1 and l2 tables */
+ init_l1_table(image);
+ init_l2_cache(image);
+
+ return 0;
+}
+
+static void free_qcow2_image(struct ext2_qcow2_image *img)
+{
+ if (!img)
+ return;
+
+ if (img->hdr)
+ ext2fs_free_mem(&img->hdr);
+
+ if (img->l1_table)
+ ext2fs_free_mem(&img->l1_table);
+
+ if (img->refcount.refcount_table)
+ ext2fs_free_mem(&img->refcount.refcount_table);
+ if (img->refcount.refcount_block)
+ ext2fs_free_mem(&img->refcount.refcount_block);
+
+ put_l2_cache(img);
+
+ ext2fs_free_mem(&img);
+}
+
+/**
+ * Put table from used list (used_head) into free list (free_head).
+ * l2_table is used to return pointer to the next used table (used_head).
+ */
+static void put_used_table(struct ext2_qcow2_image *img,
+ struct ext2_qcow2_l2_table **l2_table)
+{
+ struct ext2_qcow2_l2_cache *cache = img->l2_cache;
+ struct ext2_qcow2_l2_table *table;
+
+ table = cache->used_head;
+ cache->used_head = table->next;
+
+ assert(table);
+ if (!table->next)
+ cache->used_tail = NULL;
+
+ /* Clean the table for case we will need to use it again */
+ memset(table->data, 0, img->cluster_size);
+ table->next = cache->free_head;
+ cache->free_head = table;
+
+ cache->free++;
+
+ *l2_table = cache->used_head;
+}
+
+static void flush_l2_cache(struct ext2_qcow2_image *image)
+{
+ blk64_t seek = 0;
+ ext2_loff_t offset;
+ struct ext2_qcow2_l2_cache *cache = image->l2_cache;
+ struct ext2_qcow2_l2_table *table = cache->used_head;
+ int fd = image->fd;
+
+ /* Store current position */
+ offset = seek_relative(fd, 0);
+
+ assert(table);
+ while (cache->free < cache->count) {
+ if (seek != table->offset) {
+ seek_set(fd, table->offset);
+ seek = table->offset;
+ }
+
+ generic_write(fd, (char *)table->data, image->cluster_size,
+ NO_BLK);
+ put_used_table(image, &table);
+ seek += image->cluster_size;
+ }
+
+ /* Restore previous position */
+ seek_set(fd, offset);
+}
+
+/**
+ * Get first free table (from free_head) and put it into tail of used list
+ * (to used_tail).
+ * l2_table is used to return pointer to moved table.
+ * Returns 1 if the cache is full, 0 otherwise.
+ */
+static void get_free_table(struct ext2_qcow2_image *image,
+ struct ext2_qcow2_l2_table **l2_table)
+{
+ struct ext2_qcow2_l2_table *table;
+ struct ext2_qcow2_l2_cache *cache = image->l2_cache;
+
+ if (0 == cache->free)
+ flush_l2_cache(image);
+
+ table = cache->free_head;
+ assert(table);
+ cache->free_head = table->next;
+
+ if (cache->used_tail)
+ cache->used_tail->next = table;
+ else
+ /* First item in the used list */
+ cache->used_head = table;
+
+ cache->used_tail = table;
+ cache->free--;
+
+ *l2_table = table;
+}
+
+static int add_l2_item(struct ext2_qcow2_image *img, blk64_t blk,
+ blk64_t data, blk64_t next)
+{
+ struct ext2_qcow2_l2_cache *cache = img->l2_cache;
+ struct ext2_qcow2_l2_table *table = cache->used_tail;
+ blk64_t l1_index = blk / img->l2_size;
+ blk64_t l2_index = blk & (img->l2_size - 1);
+ int ret = 0;
+
+ /*
+ * Need to create new table if it does not exist,
+ * or if it is full
+ */
+ if (!table || (table->l1_index != l1_index)) {
+ get_free_table(img, &table);
+ table->l1_index = l1_index;
+ table->offset = cache->next_offset;
+ cache->next_offset = next;
+ img->l1_table[l1_index] =
+ ext2fs_cpu_to_be64(table->offset | QCOW_OFLAG_COPIED);
+ ret++;
+ }
+
+ table->data[l2_index] = ext2fs_cpu_to_be64(data | QCOW_OFLAG_COPIED);
+ return ret;
+}
+
+static int update_refcount(int fd, struct ext2_qcow2_image *img,
+ blk64_t offset, blk64_t rfblk_pos)
+{
+ struct ext2_qcow2_refcount *ref;
+ __u32 table_index;
+ int ret = 0;
+
+ ref = &(img->refcount);
+ table_index = offset >> (2 * img->cluster_bits - 1);
+
+ /*
+ * Need to create new refcount block when the offset addresses
+ * another item in the refcount table
+ */
+ if (table_index != ref->refcount_table_index) {
+
+ seek_set(fd, ref->refcount_block_offset);
+
+ generic_write(fd, (char *)ref->refcount_block,
+ img->cluster_size, NO_BLK);
+ memset(ref->refcount_block, 0, img->cluster_size);
+
+ ref->refcount_table[ref->refcount_table_index] =
+ ext2fs_cpu_to_be64(ref->refcount_block_offset);
+ ref->refcount_block_offset = rfblk_pos;
+ ref->refcount_block_index = 0;
+ ref->refcount_table_index = table_index;
+ ret++;
+ }
+
+ /*
+ * We are relying on the fact that we are creating the qcow2
+ * image sequentially, hence we will always allocate refcount
+ * block items sequentialy.
+ */
+ ref->refcount_block[ref->refcount_block_index] = ext2fs_cpu_to_be16(1);
+ ref->refcount_block_index++;
+ return ret;
+}
+
+static int sync_refcount(int fd, struct ext2_qcow2_image *img)
+{
+ struct ext2_qcow2_refcount *ref;
+
+ ref = &(img->refcount);
+
+ ref->refcount_table[ref->refcount_table_index] =
+ ext2fs_cpu_to_be64(ref->refcount_block_offset);
+ seek_set(fd, ref->refcount_table_offset);
+ generic_write(fd, (char *)ref->refcount_table,
+ ref->refcount_table_clusters << img->cluster_bits, NO_BLK);
+
+ seek_set(fd, ref->refcount_block_offset);
+ generic_write(fd, (char *)ref->refcount_block, img->cluster_size,
+ NO_BLK);
+ return 0;
+}
+
+static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
+{
+ errcode_t retval;
+ blk64_t blk, offset, size, end;
+ char *buf;
+ struct ext2_qcow2_image *img;
+ unsigned int header_size;
+
+ /* allocate struct ext2_qcow2_image */
+ retval = ext2fs_get_mem(sizeof(struct ext2_qcow2_image), &img);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while allocating ext2_qcow2_image"));
+ exit(1);
+ }
+
+ retval = initialize_qcow2_image(fd, fs, img);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while initializing ext2_qcow2_image"));
+ exit(1);
+ }
+ header_size = align_offset(sizeof(struct ext2_qcow2_hdr),
+ img->cluster_size);
+ write_header(fd, img->hdr, sizeof(struct ext2_qcow2_hdr), header_size);
+
+ /* Refcount all qcow2 related metadata up to refcount_block_offset */
+ end = img->refcount.refcount_block_offset;
+ seek_set(fd, end);
+ blk = end + img->cluster_size;
+ for (offset = 0; offset <= end; offset += img->cluster_size) {
+ if (update_refcount(fd, img, offset, blk)) {
+ blk += img->cluster_size;
+ /*
+ * If we create new refcount block, we need to refcount
+ * it as well.
+ */
+ end += img->cluster_size;
+ }
+ }
+ seek_set(fd, offset);
+
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval) {
+ com_err(program_name, retval, _("while allocating buffer"));
+ exit(1);
+ }
+ /* Write qcow2 data blocks */
+ for (blk = 0; blk < ext2fs_blocks_count(fs->super); blk++) {
+ if ((blk >= fs->super->s_first_data_block) &&
+ ext2fs_test_block_bitmap2(meta_block_map, blk)) {
+ retval = io_channel_read_blk64(fs->io, blk, 1, buf);
+ if (retval) {
+ com_err(program_name, retval,
+ _("error reading block %llu"), blk);
+ continue;
+ }
+ if (scramble_block_map &&
+ ext2fs_test_block_bitmap2(scramble_block_map, blk))
+ scramble_dir_block(fs, blk, buf);
+ if (check_zero_block(buf, fs->blocksize))
+ continue;
+
+ if (update_refcount(fd, img, offset, offset)) {
+ /* Make space for another refcount block */
+ offset += img->cluster_size;
+ seek_set(fd, offset);
+ /*
+ * We have created the new refcount block, this
+ * means that we need to refcount it as well.
+ * So the previous update_refcount refcounted
+ * the block itself and now we are going to
+ * create refcount for data. New refcount
+ * block should not be created!
+ */
+ if (update_refcount(fd, img, offset, offset)) {
+ fprintf(stderr, _("Programming error: "
+ "multiple sequential refcount "
+ "blocks created!\n"));
+ exit(1);
+ }
+ }
+
+ generic_write(fd, buf, fs->blocksize, blk);
+
+ if (add_l2_item(img, blk, offset,
+ offset + img->cluster_size)) {
+ offset += img->cluster_size;
+ if (update_refcount(fd, img, offset,
+ offset + img->cluster_size)) {
+ offset += img->cluster_size;
+ if (update_refcount(fd, img, offset,
+ offset)) {
+ fprintf(stderr,
+ _("Programming error: multiple sequential refcount "
+ "blocks created!\n"));
+ exit(1);
+ }
+ }
+ offset += img->cluster_size;
+ seek_set(fd, offset);
+ continue;
+ }
+
+ offset += img->cluster_size;
+ }
+ }
+ update_refcount(fd, img, offset, offset);
+ flush_l2_cache(img);
+ sync_refcount(fd, img);
+
+ /* Write l1_table*/
+ seek_set(fd, img->l1_offset);
+ size = img->l1_size * sizeof(__u64);
+ generic_write(fd, (char *)img->l1_table, size, NO_BLK);
+
+ ext2fs_free_mem(&buf);
+ free_qcow2_image(img);
+}
+
+static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
+{
+ struct process_block_struct pb;
+ struct ext2_inode inode;
+ ext2_inode_scan scan;
+ ext2_ino_t ino;
+ errcode_t retval;
+ char * block_buf;
+
+ meta_blocks_count = 0;
+ retval = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
+ &meta_block_map);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while allocating block bitmap"));
+ exit(1);
+ }
+
+ if (flags & E2IMAGE_SCRAMBLE_FLAG) {
+ retval = ext2fs_allocate_block_bitmap(fs, "scramble block map",
+ &scramble_block_map);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while allocating scramble block bitmap"));
+ exit(1);
+ }
+ }
+
+ mark_table_blocks(fs);
+ if (show_progress)
+ printf(_("Scanning inodes...\n"));
+
+ retval = ext2fs_open_inode_scan(fs, 0, &scan);
+ if (retval) {
+ com_err(program_name, retval,"%s",
+ _("while opening inode scan"));
+ exit(1);
+ }
+
+ retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
+ if (retval) {
+ com_err(program_name, 0, "%s",
+ _("Can't allocate block buffer"));
+ exit(1);
+ }
+
+ use_inode_shortcuts(fs, 1);
+ stashed_inode = &inode;
+ while (1) {
+ retval = ext2fs_get_next_inode(scan, &ino, &inode);
+ if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
+ continue;
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while getting next inode"));
+ exit(1);
+ }
+ if (ino == 0)
+ break;
+ if (!inode.i_links_count)
+ continue;
+ if (ext2fs_file_acl_block(fs, &inode)) {
+ ext2fs_mark_block_bitmap2(meta_block_map,
+ ext2fs_file_acl_block(fs, &inode));
+ meta_blocks_count++;
+ }
+ if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
+ continue;
+
+ stashed_ino = ino;
+ pb.ino = ino;
+ pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
+ if (LINUX_S_ISDIR(inode.i_mode) ||
+ (LINUX_S_ISLNK(inode.i_mode) &&
+ ext2fs_inode_has_valid_blocks2(fs, &inode)) ||
+ ino == fs->super->s_journal_inum) {
+ retval = ext2fs_block_iterate3(fs, ino,
+ BLOCK_FLAG_READ_ONLY, block_buf,
+ process_dir_block, &pb);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while iterating over inode %u"),
+ ino);
+ exit(1);
+ }
+ } else {
+ if ((inode.i_flags & EXT4_EXTENTS_FL) ||
+ inode.i_block[EXT2_IND_BLOCK] ||
+ inode.i_block[EXT2_DIND_BLOCK] ||
+ inode.i_block[EXT2_TIND_BLOCK] || all_data) {
+ retval = ext2fs_block_iterate3(fs,
+ ino, BLOCK_FLAG_READ_ONLY, block_buf,
+ process_file_block, &pb);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while iterating over inode %u"), ino);
+ exit(1);
+ }
+ }
+ }
+ }
+ use_inode_shortcuts(fs, 0);
+
+ if (type & E2IMAGE_QCOW2)
+ output_qcow2_meta_data_blocks(fs, fd);
+ else
+ output_meta_data_blocks(fs, fd, flags);
+
+ ext2fs_free_mem(&block_buf);
+ ext2fs_close_inode_scan(scan);
+ ext2fs_free_block_bitmap(meta_block_map);
+ if (type & E2IMAGE_SCRAMBLE_FLAG)
+ ext2fs_free_block_bitmap(scramble_block_map);
+}
+
+static void install_image(char *device, char *image_fn, int type)
+{
+ errcode_t retval;
+ ext2_filsys fs;
+ int open_flag = EXT2_FLAG_IMAGE_FILE | EXT2_FLAG_64BITS;
+ int fd = 0;
+ io_manager io_ptr;
+ io_channel io;
+
+ if (type) {
+ com_err(program_name, 0, _("Raw and qcow2 images cannot"
+ "be installed"));
+ exit(1);
+ }
+
+#ifdef CONFIG_TESTIO_DEBUG
+ if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
+ io_ptr = test_io_manager;
+ test_io_backing_manager = unix_io_manager;
+ } else
+#endif
+ io_ptr = unix_io_manager;
+
+ retval = ext2fs_open (image_fn, open_flag, 0, 0,
+ io_ptr, &fs);
+ if (retval) {
+ com_err (program_name, retval, _("while trying to open %s"),
+ image_fn);
+ exit(1);
+ }
+
+ retval = ext2fs_read_bitmaps (fs);
+ if (retval) {
+ com_err(program_name, retval, _("error reading bitmaps"));
+ exit(1);
+ }
+
+ fd = ext2fs_open_file(image_fn, O_RDONLY, 0);
+ if (fd < 0) {
+ perror(image_fn);
+ exit(1);
+ }
+
+ retval = io_ptr->open(device, IO_FLAG_RW, &io);
+ if (retval) {
+ com_err(device, 0, _("while opening device file"));
+ exit(1);
+ }
+
+ ext2fs_rewrite_to_io(fs, io);
+
+ seek_set(fd, fs->image_header->offset_inode);
+
+ retval = ext2fs_image_inode_read(fs, fd, 0);
+ if (retval) {
+ com_err(image_fn, 0, "while restoring the image table");
+ exit(1);
+ }
+
+ close(fd);
+ ext2fs_close (fs);
+}
+
+static struct ext2_qcow2_hdr *check_qcow2_image(int *fd, char *name)
+{
+
+ *fd = ext2fs_open_file(name, O_RDONLY, 0600);
+ if (*fd < 0)
+ return NULL;
+
+ return qcow2_read_header(*fd);
+}
+
+int main (int argc, char ** argv)
+{
+ int c;
+ errcode_t retval;
+ ext2_filsys fs;
+ char *image_fn, offset_opt[64];
+ struct ext2_qcow2_hdr *header = NULL;
+ int open_flag = EXT2_FLAG_64BITS;
+ int img_type = 0;
+ int flags = 0;
+ int mount_flags = 0;
+ int qcow2_fd = 0;
+ int fd = 0;
+ int ret = 0;
+ int ignore_rw_mount = 0;
+ int check = 0;
+ struct stat st;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+ fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION,
+ E2FSPROGS_DATE);
+ if (argc && *argv)
+ program_name = *argv;
+ add_error_table(&et_ext2_error_table);
+ while ((c = getopt(argc, argv, "nrsIQafo:O:pc")) != EOF)
+ switch (c) {
+ case 'I':
+ flags |= E2IMAGE_INSTALL_FLAG;
+ break;
+ case 'Q':
+ if (img_type)
+ usage();
+ img_type |= E2IMAGE_QCOW2;
+ break;
+ case 'r':
+ if (img_type)
+ usage();
+ img_type |= E2IMAGE_RAW;
+ break;
+ case 's':
+ flags |= E2IMAGE_SCRAMBLE_FLAG;
+ break;
+ case 'a':
+ all_data = 1;
+ break;
+ case 'f':
+ ignore_rw_mount = 1;
+ break;
+ case 'n':
+ nop_flag = 1;
+ break;
+ case 'o':
+ source_offset = strtoull(optarg, NULL, 0);
+ break;
+ case 'O':
+ dest_offset = strtoull(optarg, NULL, 0);
+ break;
+ case 'p':
+ show_progress = 1;
+ break;
+ case 'c':
+ check = 1;
+ break;
+ default:
+ usage();
+ }
+ if (optind == argc - 1 &&
+ (source_offset || dest_offset))
+ move_mode = 1;
+ else if (optind != argc - 2 )
+ usage();
+
+ if (all_data && !img_type) {
+ com_err(program_name, 0, _("-a option can only be used "
+ "with raw or QCOW2 images."));
+ exit(1);
+ }
+ if ((source_offset || dest_offset) && img_type != E2IMAGE_RAW) {
+ com_err(program_name, 0,
+ _("Offsets are only allowed with raw images."));
+ exit(1);
+ }
+ if (move_mode && img_type != E2IMAGE_RAW) {
+ com_err(program_name, 0,
+ _("Move mode is only allowed with raw images."));
+ exit(1);
+ }
+ if (move_mode && !all_data) {
+ com_err(program_name, 0,
+ _("Move mode requires all data mode."));
+ exit(1);
+ }
+ device_name = argv[optind];
+ if (move_mode)
+ image_fn = device_name;
+ else image_fn = argv[optind+1];
+
+ retval = ext2fs_check_if_mounted(device_name, &mount_flags);
+ if (retval) {
+ com_err(program_name, retval, _("checking if mounted"));
+ exit(1);
+ }
+
+ if (img_type && !ignore_rw_mount &&
+ (mount_flags & EXT2_MF_MOUNTED) &&
+ !(mount_flags & EXT2_MF_READONLY)) {
+ fprintf(stderr, _("\nRunning e2image on a R/W mounted "
+ "filesystem can result in an\n"
+ "inconsistent image which will not be useful "
+ "for debugging purposes.\n"
+ "Use -f option if you really want to do that.\n"));
+ exit(1);
+ }
+
+ if (flags & E2IMAGE_INSTALL_FLAG) {
+ install_image(device_name, image_fn, img_type);
+ exit (0);
+ }
+
+ if (img_type & E2IMAGE_RAW) {
+ header = check_qcow2_image(&qcow2_fd, device_name);
+ if (header) {
+ flags |= E2IMAGE_IS_QCOW2_FLAG;
+ goto skip_device;
+ }
+ }
+ sprintf(offset_opt, "offset=%llu", source_offset);
+ retval = ext2fs_open2(device_name, offset_opt, open_flag, 0, 0,
+ unix_io_manager, &fs);
+ if (retval) {
+ com_err (program_name, retval, _("while trying to open %s"),
+ device_name);
+ fputs(_("Couldn't find valid filesystem superblock.\n"), stdout);
+ exit(1);
+ }
+
+skip_device:
+ if (strcmp(image_fn, "-") == 0)
+ fd = 1;
+ else {
+ int o_flags = O_CREAT|O_RDWR;
+
+ if (img_type != E2IMAGE_RAW)
+ o_flags |= O_TRUNC;
+ if (access(image_fn, F_OK) != 0)
+ flags |= E2IMAGE_CHECK_ZERO_FLAG;
+ fd = ext2fs_open_file(image_fn, o_flags, 0600);
+ if (fd < 0) {
+ com_err(program_name, errno,
+ _("while trying to open %s"), image_fn);
+ exit(1);
+ }
+ }
+ if (dest_offset)
+ seek_set(fd, dest_offset);
+
+ if ((img_type & E2IMAGE_QCOW2) && (fd == 1)) {
+ com_err(program_name, 0, _("QCOW2 image can not be written to "
+ "the stdout!\n"));
+ exit(1);
+ }
+ if (fd != 1) {
+ if (fstat(fd, &st)) {
+ com_err(program_name, 0, "Can not stat output\n");
+ exit(1);
+ }
+ if (S_ISBLK(st.st_mode))
+ output_is_blk = 1;
+ }
+ if (flags & E2IMAGE_IS_QCOW2_FLAG) {
+ ret = qcow2_write_raw_image(qcow2_fd, fd, header);
+ if (ret) {
+ if (ret == -QCOW_COMPRESSED)
+ fprintf(stderr, _("Image (%s) is compressed\n"),
+ image_fn);
+ if (ret == -QCOW_ENCRYPTED)
+ fprintf(stderr, _("Image (%s) is encrypted\n"),
+ image_fn);
+ com_err(program_name, ret,
+ _("while trying to convert qcow2 image"
+ " (%s) into raw image (%s)"),
+ device_name, image_fn);
+ }
+ goto out;
+ }
+
+ if (check) {
+ if (img_type != E2IMAGE_RAW) {
+ fprintf(stderr, _("The -c option only supported "
+ "in raw mode\n"));
+ exit(1);
+ }
+ if (fd == 1) {
+ fprintf(stderr, _("The -c option is not supported "
+ "when writing to stdout\n"));
+ exit(1);
+ }
+ retval = ext2fs_get_mem(fs->blocksize, &check_buf);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while allocating check_buf"));
+ exit(1);
+ }
+ }
+ if (show_progress && (img_type != E2IMAGE_RAW)) {
+ fprintf(stderr, _("The -p option only supported "
+ "in raw mode\n"));
+ exit(1);
+ }
+ if (img_type)
+ write_raw_image_file(fs, fd, img_type, flags);
+ else
+ write_image_file(fs, fd);
+
+ ext2fs_close (fs);
+ if (check)
+ printf(_("%d blocks already contained the data to be copied.\n"),
+ skipped_blocks);
+
+out:
+ if (header)
+ free(header);
+ if (qcow2_fd)
+ close(qcow2_fd);
+ remove_error_table(&et_ext2_error_table);
+ return ret;
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2initrd_helper.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2initrd_helper.c
new file mode 100644
index 0000000..765716d
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2initrd_helper.c
@@ -0,0 +1,397 @@
+/*
+ * e2initrd_helper.c - Get the filesystem table
+ *
+ * Copyright 2004 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <unistd.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <utime.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern int optind;
+extern char *optarg;
+#endif
+
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+#include "blkid/blkid.h"
+
+#include "../version.h"
+#include "nls-enable.h"
+
+static const char * program_name = "e2initrd_helper";
+static char * device_name;
+static int open_flag;
+static int root_type;
+static blkid_cache cache = NULL;
+
+struct mem_file {
+ char *buf;
+ int size;
+ int ptr;
+};
+
+struct fs_info {
+ char *device;
+ char *mountpt;
+ char *type;
+ char *opts;
+ int freq;
+ int passno;
+ int flags;
+ struct fs_info *next;
+};
+
+static void usage(void)
+{
+ fprintf(stderr,
+ _("Usage: %s -r device\n"), program_name);
+ exit (1);
+}
+
+static errcode_t get_file(ext2_filsys fs, const char * filename,
+ struct mem_file *ret_file)
+{
+ errcode_t retval;
+ char *buf;
+ ext2_file_t e2_file = NULL;
+ unsigned int got;
+ struct ext2_inode inode;
+ ext2_ino_t ino;
+
+ ret_file->buf = 0;
+ ret_file->size = 0;
+ ret_file->ptr = 0;
+
+ retval = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
+ filename, &ino);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_read_inode(fs, ino, &inode);
+ if (retval)
+ return retval;
+
+ if (inode.i_size_high || (inode.i_size > 65536))
+ return EFBIG;
+
+ buf = malloc(inode.i_size + 1);
+ if (!buf)
+ return ENOMEM;
+ memset(buf, 0, inode.i_size+1);
+
+ retval = ext2fs_file_open(fs, ino, 0, &e2_file);
+ if (retval)
+ goto errout;
+
+ retval = ext2fs_file_read(e2_file, buf, inode.i_size, &got);
+ if (retval)
+ goto errout;
+
+ retval = ext2fs_file_close(e2_file);
+ if (retval)
+ goto errout;
+
+ ret_file->buf = buf;
+ ret_file->size = (int) got;
+ return 0;
+
+errout:
+ free(buf);
+ if (e2_file)
+ ext2fs_file_close(e2_file);
+ return retval;
+}
+
+static char *get_line(struct mem_file *file)
+{
+ char *cp, *ret;
+ int s = 0;
+
+ cp = file->buf + file->ptr;
+ while (*cp && *cp != '\n') {
+ cp++;
+ s++;
+ }
+ ret = malloc(s+1);
+ if (!ret)
+ return 0;
+ ret[s]=0;
+ memcpy(ret, file->buf + file->ptr, s);
+ while (*cp && (*cp == '\n' || *cp == '\r')) {
+ cp++;
+ s++;
+ }
+ file->ptr += s;
+ return ret;
+}
+
+static int mem_file_eof(struct mem_file *file)
+{
+ return (file->ptr >= file->size);
+}
+
+/*
+ * fstab parsing code
+ */
+static char *string_copy(const char *s)
+{
+ char *ret;
+
+ if (!s)
+ return 0;
+ ret = malloc(strlen(s)+1);
+ if (ret)
+ strcpy(ret, s);
+ return ret;
+}
+
+static char *skip_over_blank(char *cp)
+{
+ while (*cp && isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static char *skip_over_word(char *cp)
+{
+ while (*cp && !isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static char *parse_word(char **buf)
+{
+ char *word, *next;
+
+ word = *buf;
+ if (*word == 0)
+ return 0;
+
+ word = skip_over_blank(word);
+ next = skip_over_word(word);
+ if (*next)
+ *next++ = 0;
+ *buf = next;
+ return word;
+}
+
+static void parse_escape(char *word)
+{
+ char *p, *q;
+ int ac, i;
+
+ if (!word)
+ return;
+
+ for (p = word, q = word; *p; p++, q++) {
+ *q = *p;
+ if (*p != '\\')
+ continue;
+ if (*++p == 0)
+ break;
+ if (*p == 't') {
+ *q = '\t';
+ continue;
+ }
+ if (*p == 'n') {
+ *q = '\n';
+ continue;
+ }
+ if (!isdigit(*p)) {
+ *q = *p;
+ continue;
+ }
+ ac = 0;
+ for (i = 0; i < 3; i++, p++) {
+ if (!isdigit(*p))
+ break;
+ ac = (ac * 8) + (*p - '0');
+ }
+ *q = ac;
+ p--;
+ }
+ *q = 0;
+}
+
+static int parse_fstab_line(char *line, struct fs_info *fs)
+{
+ char *dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
+
+ if ((cp = strchr(line, '#')))
+ *cp = 0; /* Ignore everything after the comment char */
+ cp = line;
+
+ device = parse_word(&cp);
+ mntpnt = parse_word(&cp);
+ type = parse_word(&cp);
+ opts = parse_word(&cp);
+ freq = parse_word(&cp);
+ passno = parse_word(&cp);
+
+ if (!device)
+ return -1; /* Allow blank lines */
+
+ if (!mntpnt || !type)
+ return -1;
+
+ parse_escape(device);
+ parse_escape(mntpnt);
+ parse_escape(type);
+ parse_escape(opts);
+ parse_escape(freq);
+ parse_escape(passno);
+
+ dev = blkid_get_devname(cache, device, NULL);
+ if (dev)
+ device = dev;
+
+ if (strchr(type, ','))
+ type = 0;
+
+ fs->device = string_copy(device);
+ fs->mountpt = string_copy(mntpnt);
+ fs->type = string_copy(type);
+ fs->opts = string_copy(opts ? opts : "");
+ fs->freq = freq ? atoi(freq) : -1;
+ fs->passno = passno ? atoi(passno) : -1;
+ fs->flags = 0;
+ fs->next = NULL;
+
+ free(dev);
+
+ return 0;
+}
+
+static void free_fstab_line(struct fs_info *fs)
+{
+ if (fs->device)
+ fs->device = 0;
+ if (fs->mountpt)
+ fs->mountpt = 0;
+ if (fs->type)
+ fs->type = 0;
+ if (fs->opts)
+ fs->opts = 0;
+ memset(fs, 0, sizeof(struct fs_info));
+}
+
+
+static void PRS(int argc, char **argv)
+{
+ int c;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+
+ while ((c = getopt(argc, argv, "rv")) != EOF) {
+ switch (c) {
+ case 'r':
+ root_type++;
+ break;
+
+ case 'v':
+ printf("%s %s (%s)\n", program_name,
+ E2FSPROGS_VERSION, E2FSPROGS_DATE);
+ break;
+ default:
+ usage();
+ }
+ }
+ if (optind < argc - 1 || optind == argc)
+ usage();
+ device_name = blkid_get_devname(NULL, argv[optind], NULL);
+ if (!device_name) {
+ com_err(program_name, 0, _("Unable to resolve '%s'"),
+ argv[optind]);
+ exit(1);
+ }
+}
+
+static void get_root_type(ext2_filsys fs)
+{
+ errcode_t retval;
+ struct mem_file file;
+ char *buf;
+ struct fs_info fs_info;
+ int ret;
+
+ retval = get_file(fs, "/etc/fstab", &file);
+ if (retval) {
+ com_err(program_name, retval, "couldn't open /etc/fstab");
+ exit(1);
+ }
+
+ while (!mem_file_eof(&file)) {
+ buf = get_line(&file);
+ if (!buf)
+ continue;
+
+ ret = parse_fstab_line(buf, &fs_info);
+ if (ret < 0)
+ goto next_line;
+
+ if (!strcmp(fs_info.mountpt, "/"))
+ printf("%s\n", fs_info.type);
+
+ free_fstab_line(&fs_info);
+
+ next_line:
+ free(buf);
+ }
+}
+
+
+int main (int argc, char ** argv)
+{
+ errcode_t retval;
+ ext2_filsys fs;
+ io_manager io_ptr;
+
+ add_error_table(&et_ext2_error_table);
+
+ blkid_get_cache(&cache, NULL);
+ PRS(argc, argv);
+
+#ifdef CONFIG_TESTIO_DEBUG
+ if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
+ io_ptr = test_io_manager;
+ test_io_backing_manager = unix_io_manager;
+ } else
+#endif
+ io_ptr = unix_io_manager;
+ retval = ext2fs_open (device_name, open_flag, 0, 0, io_ptr, &fs);
+ if (retval)
+ exit(1);
+
+ if (root_type)
+ get_root_type(fs);
+
+ remove_error_table(&et_ext2_error_table);
+ return (ext2fs_close (fs) ? 1 : 0);
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2label.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2label.8.in
new file mode 100644
index 0000000..aff08d9
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2label.8.in
@@ -0,0 +1,53 @@
+.\" -*- nroff -*-
+.\" Copyright 1993, 1994, 1995 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH E2LABEL 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+e2label \- Change the label on an ext2/ext3/ext4 filesystem
+.SH SYNOPSIS
+.B e2label
+.I device
+[
+.I new-label
+]
+.SH DESCRIPTION
+.B e2label
+will display or change the filesystem label on the ext2, ext3, or ext4
+filesystem located on
+.I device.
+.PP
+If the optional argument
+.I new-label
+is not present,
+.B e2label
+will simply display the current filesystem label.
+.PP
+If the optional argument
+.I new-label
+is present, then
+.B e2label
+will set the filesystem label to be
+.IR new-label .
+Ext2 filesystem labels can be at most 16 characters long; if
+.I new-label
+is longer than 16 characters,
+.B e2label
+will truncate it and print a warning message.
+.PP
+It is also possible to set the filesystem label using the
+.B \-L
+option of
+.BR tune2fs (8).
+.PP
+.SH AUTHOR
+.B e2label
+was written by Theodore Ts'o (tytso@mit.edu).
+.SH AVAILABILITY
+.B e2label
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR mke2fs (8),
+.BR tune2fs (8)
+
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2label.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2label.c
new file mode 100644
index 0000000..bc87a42
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2label.c
@@ -0,0 +1,121 @@
+/*
+ * e2label.c - Print or change the volume label on an ext2 fs
+ *
+ * Written by Andries Brouwer (aeb@cwi.nl), 970714
+ *
+ * Copyright 1997, 1998 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <termios.h>
+#include <time.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include "nls-enable.h"
+
+#define EXT2_SUPER_MAGIC 0xEF53
+
+#define VOLNAMSZ 16
+
+struct ext2_super_block {
+ char s_dummy0[56];
+ unsigned char s_magic[2];
+ char s_dummy1[62];
+ char s_volume_name[VOLNAMSZ];
+ char s_last_mounted[64];
+ char s_dummy2[824];
+} sb;
+
+static int open_e2fs (char *dev, int mode)
+{
+ int fd;
+
+ fd = open(dev, mode);
+ if (fd < 0) {
+ perror(dev);
+ fprintf (stderr, _("e2label: cannot open %s\n"), dev);
+ exit(1);
+ }
+ if (lseek(fd, 1024, SEEK_SET) != 1024) {
+ perror(dev);
+ fprintf (stderr, _("e2label: cannot seek to superblock\n"));
+ exit(1);
+ }
+ if (read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb)) {
+ perror(dev);
+ fprintf (stderr, _("e2label: error reading superblock\n"));
+ exit(1);
+ }
+ if (sb.s_magic[0] + 256*sb.s_magic[1] != EXT2_SUPER_MAGIC) {
+ fprintf (stderr, _("e2label: not an ext2 filesystem\n"));
+ exit(1);
+ }
+
+ return fd;
+}
+
+static void print_label (char *dev)
+{
+ char label[VOLNAMSZ+1];
+
+ open_e2fs (dev, O_RDONLY);
+ strncpy(label, sb.s_volume_name, VOLNAMSZ);
+ label[VOLNAMSZ] = 0;
+ printf("%s\n", label);
+}
+
+static void change_label (char *dev, char *label)
+{
+ int fd;
+
+ fd = open_e2fs(dev, O_RDWR);
+ memset(sb.s_volume_name, 0, VOLNAMSZ);
+ strncpy(sb.s_volume_name, label, VOLNAMSZ);
+ if (strlen(label) > VOLNAMSZ)
+ fprintf(stderr, _("Warning: label too long, truncating.\n"));
+ if (lseek(fd, 1024, SEEK_SET) != 1024) {
+ perror(dev);
+ fprintf (stderr, _("e2label: cannot seek to superblock again\n"));
+ exit(1);
+ }
+ if (write(fd, (char *) &sb, sizeof(sb)) != sizeof(sb)) {
+ perror(dev);
+ fprintf (stderr, _("e2label: error writing superblock\n"));
+ exit(1);
+ }
+}
+
+int main (int argc, char ** argv)
+{
+ if (argc == 2)
+ print_label(argv[1]);
+ else if (argc == 3)
+ change_label(argv[1], argv[2]);
+ else {
+ fprintf(stderr, _("Usage: e2label device [newlabel]\n"));
+ exit(1);
+ }
+ return 0;
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2undo.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2undo.8.in
new file mode 100644
index 0000000..4bf0798
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2undo.8.in
@@ -0,0 +1,44 @@
+.\" -*- nroff -*-
+.\" Copyright 2008 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH E2UNDO 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+e2undo \- Replay an undo log for an ext2/ext3/ext4 filesystem
+.SH SYNOPSIS
+.B e2undo
+[
+.B \-f
+]
+.I undo_log device
+.SH DESCRIPTION
+.B e2undo
+will replay the undo log
+.I undo_log
+for an ext2/ext3/ext4 filesystem found on
+.IR device .
+This can be
+used to undo a failed operation by an e2fsprogs program.
+.SH OPTIONS
+.TP
+.B \-f
+Normally,
+.B e2undo
+will check the filesystem UUID and last modified time to make sure the
+undo log matches with the filesystem on the device. If they do not
+match,
+.B e2undo
+will refuse to apply the undo log as a safety mechanism. The
+.B \-f
+option disables this safety mechanism.
+.SH AUTHOR
+.B e2undo
+was written by Aneesh Kumar K.V. (aneesh.kumar@linux.vnet.ibm.com)
+.SH AVAILABILITY
+.B e2undo
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR mke2fs (8),
+.BR tune2fs (8)
+
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2undo.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2undo.c
new file mode 100644
index 0000000..a43c26f
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e2undo.c
@@ -0,0 +1,225 @@
+/*
+ * e2undo.c - Replay an undo log onto an ext2/3/4 filesystem
+ *
+ * Copyright IBM Corporation, 2007
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#include <fcntl.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include "ext2fs/tdb.h"
+#include "ext2fs/ext2fs.h"
+#include "nls-enable.h"
+
+static unsigned char mtime_key[] = "filesystem MTIME";
+static unsigned char uuid_key[] = "filesystem UUID";
+static unsigned char blksize_key[] = "filesystem BLKSIZE";
+
+static char *prg_name;
+
+static void usage(void)
+{
+ fprintf(stderr,
+ _("Usage: %s <transaction file> <filesystem>\n"), prg_name);
+ exit(1);
+}
+
+static int check_filesystem(TDB_CONTEXT *tdb, io_channel channel)
+{
+ __u32 s_mtime;
+ __u8 s_uuid[16];
+ errcode_t retval;
+ TDB_DATA tdb_key, tdb_data;
+ struct ext2_super_block super;
+
+ io_channel_set_blksize(channel, SUPERBLOCK_OFFSET);
+ retval = io_channel_read_blk64(channel, 1, -SUPERBLOCK_SIZE, &super);
+ if (retval) {
+ com_err(prg_name, retval,
+ "%s", _("Failed to read the file system data \n"));
+ return retval;
+ }
+
+ tdb_key.dptr = mtime_key;
+ tdb_key.dsize = sizeof(mtime_key);
+ tdb_data = tdb_fetch(tdb, tdb_key);
+ if (!tdb_data.dptr) {
+ retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+ com_err(prg_name, retval,
+ _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+ return retval;
+ }
+
+ s_mtime = *(__u32 *)tdb_data.dptr;
+ if (super.s_mtime != s_mtime) {
+
+ com_err(prg_name, 0,
+ _("The file system Mount time didn't match %u\n"),
+ s_mtime);
+
+ return -1;
+ }
+
+
+ tdb_key.dptr = uuid_key;
+ tdb_key.dsize = sizeof(uuid_key);
+ tdb_data = tdb_fetch(tdb, tdb_key);
+ if (!tdb_data.dptr) {
+ retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+ com_err(prg_name, retval,
+ _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+ return retval;
+ }
+ memcpy(s_uuid, tdb_data.dptr, sizeof(s_uuid));
+ if (memcmp(s_uuid, super.s_uuid, sizeof(s_uuid))) {
+ com_err(prg_name, 0, "%s",
+ _("The file system UUID didn't match \n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int set_blk_size(TDB_CONTEXT *tdb, io_channel channel)
+{
+ int block_size;
+ errcode_t retval;
+ TDB_DATA tdb_key, tdb_data;
+
+ tdb_key.dptr = blksize_key;
+ tdb_key.dsize = sizeof(blksize_key);
+ tdb_data = tdb_fetch(tdb, tdb_key);
+ if (!tdb_data.dptr) {
+ retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+ com_err(prg_name, retval,
+ _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+ return retval;
+ }
+
+ block_size = *(int *)tdb_data.dptr;
+#ifdef DEBUG
+ printf("Block size %d\n", block_size);
+#endif
+ io_channel_set_blksize(channel, block_size);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int c,force = 0;
+ TDB_CONTEXT *tdb;
+ TDB_DATA key, data;
+ io_channel channel;
+ errcode_t retval;
+ int mount_flags;
+ blk64_t blk_num;
+ char *device_name, *tdb_file;
+ io_manager manager = unix_io_manager;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+ add_error_table(&et_ext2_error_table);
+
+ prg_name = argv[0];
+ while((c = getopt(argc, argv, "f")) != EOF) {
+ switch (c) {
+ case 'f':
+ force = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (argc != optind + 2)
+ usage();
+
+ tdb_file = argv[optind];
+ device_name = argv[optind+1];
+
+ tdb = tdb_open(tdb_file, 0, 0, O_RDONLY, 0600);
+
+ if (!tdb) {
+ com_err(prg_name, errno,
+ _("Failed tdb_open %s\n"), tdb_file);
+ exit(1);
+ }
+
+ retval = ext2fs_check_if_mounted(device_name, &mount_flags);
+ if (retval) {
+ com_err(prg_name, retval, _("Error while determining whether "
+ "%s is mounted.\n"), device_name);
+ exit(1);
+ }
+
+ if (mount_flags & EXT2_MF_MOUNTED) {
+ com_err(prg_name, retval, "%s", _("e2undo should only be run "
+ "on unmounted file system\n"));
+ exit(1);
+ }
+
+ retval = manager->open(device_name,
+ IO_FLAG_EXCLUSIVE | IO_FLAG_RW, &channel);
+ if (retval) {
+ com_err(prg_name, retval,
+ _("Failed to open %s\n"), device_name);
+ exit(1);
+ }
+
+ if (!force && check_filesystem(tdb, channel)) {
+ exit(1);
+ }
+
+ if (set_blk_size(tdb, channel)) {
+ exit(1);
+ }
+
+ for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key)) {
+ if (!strcmp((char *) key.dptr, (char *) mtime_key) ||
+ !strcmp((char *) key.dptr, (char *) uuid_key) ||
+ !strcmp((char *) key.dptr, (char *) blksize_key)) {
+ continue;
+ }
+
+ data = tdb_fetch(tdb, key);
+ if (!data.dptr) {
+ com_err(prg_name, 0,
+ _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+ exit(1);
+ }
+ blk_num = *(blk64_t *)key.dptr;
+ printf(_("Replayed transaction of size %zd at location %llu\n"),
+ data.dsize, blk_num);
+ retval = io_channel_write_blk64(channel, blk_num,
+ -data.dsize, data.dptr);
+ if (retval == -1) {
+ com_err(prg_name, retval,
+ _("Failed write %s\n"),
+ strerror(errno));
+ exit(1);
+ }
+ }
+ io_channel_close(channel);
+ tdb_close(tdb);
+
+ return 0;
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e4defrag.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e4defrag.8.in
new file mode 100644
index 0000000..75e1bc9
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e4defrag.8.in
@@ -0,0 +1,80 @@
+.TH E4DEFRAG 8 "May 2009" "e4defrag version 2.0"
+.SH NAME
+e4defrag \- online defragmenter for ext4 filesystem
+.SH SYNOPSIS
+.B e4defrag
+[
+.B \-c
+]
+[
+.B \-v
+]
+.I target
+\&...
+.SH DESCRIPTION
+.B e4defrag
+reduces fragmentation of extent based file. The file targeted by
+.B e4defrag
+is created on ext4 filesystem made with "-O extent" option (see
+.BR mke2fs (8)).
+The targeted file gets more contiguous blocks and improves the file access
+speed.
+.PP
+.I target
+is a regular file, a directory, or a device that is mounted as ext4 filesystem.
+If
+.I target
+is a directory,
+.B e4defrag
+reduces fragmentation of all files in it. If
+.I target
+is a device,
+.B e4defrag
+gets the mount point of it and reduces fragmentation of all files in this mount
+point.
+.SH OPTIONS
+.TP
+.B \-c
+Get a current fragmentation count and an ideal fragmentation count, and
+calculate fragmentation score based on them. By seeing this score, we can
+determine whether we should execute
+.B e4defrag
+to
+.IR target .
+When used with
+.B \-v
+option, the current fragmentation count and the ideal fragmentation count are
+printed for each file.
+.IP
+Also this option outputs the average data size in one extent. If you see it,
+you'll find the file has ideal extents or not. Note that the maximum extent
+size is 131072KB in ext4 filesystem (if block size is 4KB).
+.IP
+If this option is specified,
+.I target
+is never defragmented.
+.TP
+.B \-v
+Print error messages and the fragmentation count before and after defrag for
+each file.
+.SH NOTES
+.B e4defrag
+does not support swap file, files in lost+found directory, and files allocated
+in indirect blocks. When
+.I target
+is a device or a mount point,
+.B e4defrag
+doesn't defragment files in mount point of other device.
+.PP
+Non-privileged users can execute
+.B e4defrag
+to their own file, but the score is not printed if
+.B \-c
+option is specified. Therefore, it is desirable to be executed by root user.
+.SH AUTHOR
+Written by Akira Fujita <a-fujita@rs.jp.nec.com> and Takashi Sato
+<t-sato@yk.jp.nec.com>.
+.SH SEE ALSO
+.BR mke2fs (8),
+.BR mount (8).
+
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e4defrag.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e4defrag.c
new file mode 100644
index 0000000..c6a5f0d
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/e4defrag.c
@@ -0,0 +1,2083 @@
+/*
+ * e4defrag.c - ext4 filesystem defragmenter
+ *
+ * Copyright (C) 2009 NEC Software Tohoku, Ltd.
+ *
+ * Author: Akira Fujita <a-fujita@rs.jp.nec.com>
+ * Takashi Sato <t-sato@yk.jp.nec.com>
+ */
+
+#ifndef _LARGEFILE_SOURCE
+#define _LARGEFILE_SOURCE
+#endif
+
+#ifndef _LARGEFILE64_SOURCE
+#define _LARGEFILE64_SOURCE
+#endif
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "config.h"
+#include <ctype.h>
+#include <dirent.h>
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <limits.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ext2fs/ext2_types.h>
+#include <ext2fs/ext2fs.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#include <ext2fs/fiemap.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/syscall.h>
+#include <sys/vfs.h>
+
+/* A relatively new ioctl interface ... */
+#ifndef EXT4_IOC_MOVE_EXT
+#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent)
+#endif
+
+/* Macro functions */
+#define PRINT_ERR_MSG(msg) fprintf(stderr, "%s\n", (msg))
+#define IN_FTW_PRINT_ERR_MSG(msg) \
+ fprintf(stderr, "\t%s\t\t[ NG ]\n", (msg))
+#define PRINT_FILE_NAME(file) fprintf(stderr, " \"%s\"\n", (file))
+#define PRINT_ERR_MSG_WITH_ERRNO(msg) \
+ fprintf(stderr, "\t%s:%s\t[ NG ]\n", (msg), strerror(errno))
+#define STATISTIC_ERR_MSG(msg) \
+ fprintf(stderr, "\t%s\n", (msg))
+#define STATISTIC_ERR_MSG_WITH_ERRNO(msg) \
+ fprintf(stderr, "\t%s:%s\n", (msg), strerror(errno))
+#define min(x, y) (((x) > (y)) ? (y) : (x))
+#define CALC_SCORE(ratio) \
+ ((ratio) > 10 ? (80 + 20 * (ratio) / 100) : (8 * (ratio)))
+/* Wrap up the free function */
+#define FREE(tmp) \
+ do { \
+ if ((tmp) != NULL) \
+ free(tmp); \
+ } while (0) \
+/* Insert list2 after list1 */
+#define insert(list1, list2) \
+ do { \
+ list2->next = list1->next; \
+ list1->next->prev = list2; \
+ list2->prev = list1; \
+ list1->next = list2; \
+ } while (0)
+
+/* To delete unused warning */
+#ifdef __GNUC__
+#define EXT2FS_ATTR(x) __attribute__(x)
+#else
+#define EXT2FS_ATTR(x)
+#endif
+
+/* The mode of defrag */
+#define DETAIL 0x01
+#define STATISTIC 0x02
+
+#define DEVNAME 0
+#define DIRNAME 1
+#define FILENAME 2
+
+#define FTW_OPEN_FD 2000
+
+#define FS_EXT4 "ext4"
+#define ROOT_UID 0
+
+#define BOUND_SCORE 55
+#define SHOW_FRAG_FILES 5
+
+/* Magic number for ext4 */
+#define EXT4_SUPER_MAGIC 0xEF53
+
+/* Definition of flex_bg */
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
+
+/* The following macro is used for ioctl FS_IOC_FIEMAP
+ * EXTENT_MAX_COUNT: the maximum number of extents for exchanging between
+ * kernel-space and user-space per ioctl
+ */
+#define EXTENT_MAX_COUNT 512
+
+/* The following macros are error message */
+#define MSG_USAGE \
+"Usage : e4defrag [-v] file...| directory...| device...\n\
+ : e4defrag -c file...| directory...| device...\n"
+
+#define NGMSG_EXT4 "Filesystem is not ext4 filesystem"
+#define NGMSG_FILE_EXTENT "Failed to get file extents"
+#define NGMSG_FILE_INFO "Failed to get file information"
+#define NGMSG_FILE_OPEN "Failed to open"
+#define NGMSG_FILE_UNREG "File is not regular file"
+#define NGMSG_LOST_FOUND "Can not process \"lost+found\""
+
+/* Data type for filesystem-wide blocks number */
+typedef unsigned long long ext4_fsblk_t;
+
+struct fiemap_extent_data {
+ __u64 len; /* blocks count */
+ __u64 logical; /* start logical block number */
+ ext4_fsblk_t physical; /* start physical block number */
+};
+
+struct fiemap_extent_list {
+ struct fiemap_extent_list *prev;
+ struct fiemap_extent_list *next;
+ struct fiemap_extent_data data; /* extent belong to file */
+};
+
+struct fiemap_extent_group {
+ struct fiemap_extent_group *prev;
+ struct fiemap_extent_group *next;
+ __u64 len; /* length of this continuous region */
+ struct fiemap_extent_list *start; /* start ext */
+ struct fiemap_extent_list *end; /* end ext */
+};
+
+struct move_extent {
+ __s32 reserved; /* original file descriptor */
+ __u32 donor_fd; /* donor file descriptor */
+ __u64 orig_start; /* logical start offset in block for orig */
+ __u64 donor_start; /* logical start offset in block for donor */
+ __u64 len; /* block length to be moved */
+ __u64 moved_len; /* moved block length */
+};
+
+struct frag_statistic_ino {
+ int now_count; /* the file's extents count of before defrag */
+ int best_count; /* the best file's extents count */
+ __u64 size_per_ext; /* size(KB) per extent */
+ float ratio; /* the ratio of fragmentation */
+ char msg_buffer[PATH_MAX + 1]; /* pathname of the file */
+};
+
+static char lost_found_dir[PATH_MAX + 1];
+static int block_size;
+static int extents_before_defrag;
+static int extents_after_defrag;
+static int mode_flag;
+static unsigned int current_uid;
+static unsigned int defraged_file_count;
+static unsigned int frag_files_before_defrag;
+static unsigned int frag_files_after_defrag;
+static unsigned int regular_count;
+static unsigned int succeed_cnt;
+static unsigned int total_count;
+static __u8 log_groups_per_flex;
+static __u32 blocks_per_group;
+static __u32 feature_incompat;
+static ext4_fsblk_t files_block_count;
+static struct frag_statistic_ino frag_rank[SHOW_FRAG_FILES];
+
+
+/* Local definitions of some syscalls glibc may not yet have */
+
+#ifndef HAVE_POSIX_FADVISE
+#warning Using locally defined posix_fadvise interface.
+
+#ifndef __NR_fadvise64_64
+#error Your kernel headers dont define __NR_fadvise64_64
+#endif
+
+/*
+ * fadvise() - Give advice about file access.
+ *
+ * @fd: defrag target file's descriptor.
+ * @offset: file offset.
+ * @len: area length.
+ * @advise: process flag.
+ */
+static int posix_fadvise(int fd, loff_t offset, size_t len, int advise)
+{
+ return syscall(__NR_fadvise64_64, fd, offset, len, advise);
+}
+#endif /* ! HAVE_FADVISE64_64 */
+
+#ifndef HAVE_SYNC_FILE_RANGE
+#warning Using locally defined sync_file_range interface.
+
+#ifndef __NR_sync_file_range
+#ifndef __NR_sync_file_range2 /* ppc */
+#error Your kernel headers dont define __NR_sync_file_range
+#endif
+#endif
+
+/*
+ * sync_file_range() - Sync file region.
+ *
+ * @fd: defrag target file's descriptor.
+ * @offset: file offset.
+ * @length: area length.
+ * @flag: process flag.
+ */
+int sync_file_range(int fd, loff_t offset, loff_t length, unsigned int flag)
+{
+#ifdef __NR_sync_file_range
+ return syscall(__NR_sync_file_range, fd, offset, length, flag);
+#else
+ return syscall(__NR_sync_file_range2, fd, flag, offset, length);
+#endif
+}
+#endif /* ! HAVE_SYNC_FILE_RANGE */
+
+#ifndef HAVE_FALLOCATE64
+#warning Using locally defined fallocate syscall interface.
+
+#ifndef __NR_fallocate
+#error Your kernel headers dont define __NR_fallocate
+#endif
+
+/*
+ * fallocate64() - Manipulate file space.
+ *
+ * @fd: defrag target file's descriptor.
+ * @mode: process flag.
+ * @offset: file offset.
+ * @len: file size.
+ */
+static int fallocate64(int fd, int mode, loff_t offset, loff_t len)
+{
+ return syscall(__NR_fallocate, fd, mode, offset, len);
+}
+#endif /* ! HAVE_FALLOCATE */
+
+/*
+ * get_mount_point() - Get device's mount point.
+ *
+ * @devname: the device's name.
+ * @mount_point: the mount point.
+ * @dir_path_len: the length of directory.
+ */
+static int get_mount_point(const char *devname, char *mount_point,
+ int dir_path_len)
+{
+ /* Refer to /etc/mtab */
+ const char *mtab = MOUNTED;
+ FILE *fp = NULL;
+ struct mntent *mnt = NULL;
+ struct stat64 sb;
+
+ if (stat64(devname, &sb) < 0) {
+ perror(NGMSG_FILE_INFO);
+ PRINT_FILE_NAME(devname);
+ return -1;
+ }
+
+ fp = setmntent(mtab, "r");
+ if (fp == NULL) {
+ perror("Couldn't access /etc/mtab");
+ return -1;
+ }
+
+ while ((mnt = getmntent(fp)) != NULL) {
+ struct stat64 ms;
+
+ /*
+ * To handle device symlinks, we see if the
+ * device number matches, not the name
+ */
+ if (stat64(mnt->mnt_fsname, &ms) < 0)
+ continue;
+ if (sb.st_rdev != ms.st_rdev)
+ continue;
+
+ endmntent(fp);
+ if (strcmp(mnt->mnt_type, FS_EXT4) == 0) {
+ strncpy(mount_point, mnt->mnt_dir,
+ dir_path_len);
+ return 0;
+ }
+ PRINT_ERR_MSG(NGMSG_EXT4);
+ return -1;
+ }
+ endmntent(fp);
+ PRINT_ERR_MSG("Filesystem is not mounted");
+ return -1;
+}
+
+/*
+ * is_ext4() - Whether on an ext4 filesystem.
+ *
+ * @file: the file's name.
+ */
+static int is_ext4(const char *file, char *devname)
+{
+ int maxlen = 0;
+ int len, ret;
+ FILE *fp = NULL;
+ char *mnt_type = NULL;
+ /* Refer to /etc/mtab */
+ const char *mtab = MOUNTED;
+ char file_path[PATH_MAX + 1];
+ struct mntent *mnt = NULL;
+ struct statfs64 fsbuf;
+
+ /* Get full path */
+ if (realpath(file, file_path) == NULL) {
+ perror("Couldn't get full path");
+ PRINT_FILE_NAME(file);
+ return -1;
+ }
+
+ if (statfs64(file_path, &fsbuf) < 0) {
+ perror("Failed to get filesystem information");
+ PRINT_FILE_NAME(file);
+ return -1;
+ }
+
+ if (fsbuf.f_type != EXT4_SUPER_MAGIC) {
+ PRINT_ERR_MSG(NGMSG_EXT4);
+ return -1;
+ }
+
+ fp = setmntent(mtab, "r");
+ if (fp == NULL) {
+ perror("Couldn't access /etc/mtab");
+ return -1;
+ }
+
+ while ((mnt = getmntent(fp)) != NULL) {
+ if (mnt->mnt_fsname[0] != '/')
+ continue;
+ len = strlen(mnt->mnt_dir);
+ ret = memcmp(file_path, mnt->mnt_dir, len);
+ if (ret != 0)
+ continue;
+
+ if (maxlen >= len)
+ continue;
+
+ maxlen = len;
+
+ mnt_type = realloc(mnt_type, strlen(mnt->mnt_type) + 1);
+ if (mnt_type == NULL) {
+ endmntent(fp);
+ return -1;
+ }
+ memset(mnt_type, 0, strlen(mnt->mnt_type) + 1);
+ strncpy(mnt_type, mnt->mnt_type, strlen(mnt->mnt_type));
+ strncpy(lost_found_dir, mnt->mnt_dir, PATH_MAX);
+ strncpy(devname, mnt->mnt_fsname, strlen(mnt->mnt_fsname) + 1);
+ }
+
+ endmntent(fp);
+ if (mnt_type && strcmp(mnt_type, FS_EXT4) == 0) {
+ FREE(mnt_type);
+ return 0;
+ } else {
+ FREE(mnt_type);
+ PRINT_ERR_MSG(NGMSG_EXT4);
+ return -1;
+ }
+}
+
+/*
+ * calc_entry_counts() - Calculate file counts.
+ *
+ * @file: file name.
+ * @buf: file info.
+ * @flag: file type.
+ * @ftwbuf: the pointer of a struct FTW.
+ */
+static int calc_entry_counts(const char *file EXT2FS_ATTR((unused)),
+ const struct stat64 *buf, int flag EXT2FS_ATTR((unused)),
+ struct FTW *ftwbuf EXT2FS_ATTR((unused)))
+{
+ if (S_ISREG(buf->st_mode))
+ regular_count++;
+
+ total_count++;
+
+ return 0;
+}
+
+/*
+ * page_in_core() - Get information on whether pages are in core.
+ *
+ * @fd: defrag target file's descriptor.
+ * @defrag_data: data used for defrag.
+ * @vec: page state array.
+ * @page_num: page number.
+ */
+static int page_in_core(int fd, struct move_extent defrag_data,
+ unsigned char **vec, unsigned int *page_num)
+{
+ long pagesize;
+ void *page = NULL;
+ loff_t offset, end_offset, length;
+
+ if (vec == NULL || *vec != NULL)
+ return -1;
+
+ pagesize = sysconf(_SC_PAGESIZE);
+ if (pagesize < 0)
+ return -1;
+ /* In mmap, offset should be a multiple of the page size */
+ offset = (loff_t)defrag_data.orig_start * block_size;
+ length = (loff_t)defrag_data.len * block_size;
+ end_offset = offset + length;
+ /* Round the offset down to the nearest multiple of pagesize */
+ offset = (offset / pagesize) * pagesize;
+ length = end_offset - offset;
+
+ page = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, offset);
+ if (page == MAP_FAILED)
+ return -1;
+
+ *page_num = 0;
+ *page_num = (length + pagesize - 1) / pagesize;
+ *vec = (unsigned char *)calloc(*page_num, 1);
+ if (*vec == NULL)
+ return -1;
+
+ /* Get information on whether pages are in core */
+ if (mincore(page, (size_t)length, *vec) == -1 ||
+ munmap(page, length) == -1) {
+ FREE(*vec);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * defrag_fadvise() - Predeclare an access pattern for file data.
+ *
+ * @fd: defrag target file's descriptor.
+ * @defrag_data: data used for defrag.
+ * @vec: page state array.
+ * @page_num: page number.
+ */
+static int defrag_fadvise(int fd, struct move_extent defrag_data,
+ unsigned char *vec, unsigned int page_num)
+{
+ int flag = 1;
+ long pagesize = sysconf(_SC_PAGESIZE);
+ int fadvise_flag = POSIX_FADV_DONTNEED;
+ int sync_flag = SYNC_FILE_RANGE_WAIT_BEFORE |
+ SYNC_FILE_RANGE_WRITE |
+ SYNC_FILE_RANGE_WAIT_AFTER;
+ unsigned int i;
+ loff_t offset;
+
+ if (pagesize < 1)
+ return -1;
+
+ offset = (loff_t)defrag_data.orig_start * block_size;
+ offset = (offset / pagesize) * pagesize;
+
+ /* Sync file for fadvise process */
+ if (sync_file_range(fd, offset,
+ (loff_t)pagesize * page_num, sync_flag) < 0)
+ return -1;
+
+ /* Try to release buffer cache which this process used,
+ * then other process can use the released buffer
+ */
+ for (i = 0; i < page_num; i++) {
+ if ((vec[i] & 0x1) == 0) {
+ offset += pagesize;
+ continue;
+ }
+ if (posix_fadvise(fd, offset, pagesize, fadvise_flag) < 0) {
+ if ((mode_flag & DETAIL) && flag) {
+ perror("\tFailed to fadvise");
+ flag = 0;
+ }
+ }
+ offset += pagesize;
+ }
+
+ return 0;
+}
+
+/*
+ * check_free_size() - Check if there's enough disk space.
+ *
+ * @fd: defrag target file's descriptor.
+ * @file: file name.
+ * @blk_count: file blocks.
+ */
+static int check_free_size(int fd, const char *file, ext4_fsblk_t blk_count)
+{
+ ext4_fsblk_t free_blk_count;
+ struct statfs64 fsbuf;
+
+ if (fstatfs64(fd, &fsbuf) < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO(
+ "Failed to get filesystem information");
+ }
+ return -1;
+ }
+
+ /* Compute free space for root and normal user separately */
+ if (current_uid == ROOT_UID)
+ free_blk_count = fsbuf.f_bfree;
+ else
+ free_blk_count = fsbuf.f_bavail;
+
+ if (free_blk_count >= blk_count)
+ return 0;
+
+ return -ENOSPC;
+}
+
+/*
+ * file_frag_count() - Get file fragment count.
+ *
+ * @fd: defrag target file's descriptor.
+ */
+static int file_frag_count(int fd)
+{
+ int ret;
+ struct fiemap fiemap_buf;
+
+ /* When fm_extent_count is 0,
+ * ioctl just get file fragment count.
+ */
+ memset(&fiemap_buf, 0, sizeof(struct fiemap));
+ fiemap_buf.fm_start = 0;
+ fiemap_buf.fm_length = FIEMAP_MAX_OFFSET;
+ fiemap_buf.fm_flags |= FIEMAP_FLAG_SYNC;
+
+ ret = ioctl(fd, FS_IOC_FIEMAP, &fiemap_buf);
+ if (ret < 0)
+ return ret;
+
+ return fiemap_buf.fm_mapped_extents;
+}
+
+/*
+ * file_check() - Check file's attributes.
+ *
+ * @fd: defrag target file's descriptor.
+ * @buf: a pointer of the struct stat64.
+ * @file: file name.
+ * @extents: file extents.
+ * @blk_count: file blocks.
+ */
+static int file_check(int fd, const struct stat64 *buf, const char *file,
+ int extents, ext4_fsblk_t blk_count)
+{
+ int ret;
+ struct flock lock;
+
+ /* Write-lock check is more reliable */
+ lock.l_type = F_WRLCK;
+ lock.l_start = 0;
+ lock.l_whence = SEEK_SET;
+ lock.l_len = 0;
+
+ /* Free space */
+ ret = check_free_size(fd, file, blk_count);
+ if (ret < 0) {
+ if ((mode_flag & DETAIL) && ret == -ENOSPC) {
+ printf("\033[79;0H\033[K[%u/%u] \"%s\"\t\t"
+ " extents: %d -> %d\n", defraged_file_count,
+ total_count, file, extents, extents);
+ IN_FTW_PRINT_ERR_MSG(
+ "Defrag size is larger than filesystem's free space");
+ }
+ return -1;
+ }
+
+ /* Access authority */
+ if (current_uid != ROOT_UID &&
+ buf->st_uid != current_uid) {
+ if (mode_flag & DETAIL) {
+ printf("\033[79;0H\033[K[%u/%u] \"%s\"\t\t"
+ " extents: %d -> %d\n", defraged_file_count,
+ total_count, file, extents, extents);
+ IN_FTW_PRINT_ERR_MSG(
+ "File is not current user's file"
+ " or current user is not root");
+ }
+ return -1;
+ }
+
+ /* Lock status */
+ if (fcntl(fd, F_GETLK, &lock) < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO(
+ "Failed to get lock information");
+ }
+ return -1;
+ } else if (lock.l_type != F_UNLCK) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ IN_FTW_PRINT_ERR_MSG("File has been locked");
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * insert_extent_by_logical() - Sequentially insert extent by logical.
+ *
+ * @ext_list_head: the head of logical extent list.
+ * @ext: the extent element which will be inserted.
+ */
+static int insert_extent_by_logical(struct fiemap_extent_list **ext_list_head,
+ struct fiemap_extent_list *ext)
+{
+ struct fiemap_extent_list *ext_list_tmp = *ext_list_head;
+
+ if (ext == NULL)
+ goto out;
+
+ /* First element */
+ if (*ext_list_head == NULL) {
+ (*ext_list_head) = ext;
+ (*ext_list_head)->prev = *ext_list_head;
+ (*ext_list_head)->next = *ext_list_head;
+ return 0;
+ }
+
+ if (ext->data.logical <= ext_list_tmp->data.logical) {
+ /* Insert before head */
+ if (ext_list_tmp->data.logical <
+ ext->data.logical + ext->data.len)
+ /* Overlap */
+ goto out;
+ /* Adjust head */
+ *ext_list_head = ext;
+ } else {
+ /* Insert into the middle or last of the list */
+ do {
+ if (ext->data.logical < ext_list_tmp->data.logical)
+ break;
+ ext_list_tmp = ext_list_tmp->next;
+ } while (ext_list_tmp != (*ext_list_head));
+ if (ext->data.logical <
+ ext_list_tmp->prev->data.logical +
+ ext_list_tmp->prev->data.len)
+ /* Overlap */
+ goto out;
+
+ if (ext_list_tmp != *ext_list_head &&
+ ext_list_tmp->data.logical <
+ ext->data.logical + ext->data.len)
+ /* Overlap */
+ goto out;
+ }
+ ext_list_tmp = ext_list_tmp->prev;
+ /* Insert "ext" after "ext_list_tmp" */
+ insert(ext_list_tmp, ext);
+ return 0;
+out:
+ errno = EINVAL;
+ return -1;
+}
+
+/*
+ * insert_extent_by_physical() - Sequentially insert extent by physical.
+ *
+ * @ext_list_head: the head of physical extent list.
+ * @ext: the extent element which will be inserted.
+ */
+static int insert_extent_by_physical(struct fiemap_extent_list **ext_list_head,
+ struct fiemap_extent_list *ext)
+{
+ struct fiemap_extent_list *ext_list_tmp = *ext_list_head;
+
+ if (ext == NULL)
+ goto out;
+
+ /* First element */
+ if (*ext_list_head == NULL) {
+ (*ext_list_head) = ext;
+ (*ext_list_head)->prev = *ext_list_head;
+ (*ext_list_head)->next = *ext_list_head;
+ return 0;
+ }
+
+ if (ext->data.physical <= ext_list_tmp->data.physical) {
+ /* Insert before head */
+ if (ext_list_tmp->data.physical <
+ ext->data.physical + ext->data.len)
+ /* Overlap */
+ goto out;
+ /* Adjust head */
+ *ext_list_head = ext;
+ } else {
+ /* Insert into the middle or last of the list */
+ do {
+ if (ext->data.physical < ext_list_tmp->data.physical)
+ break;
+ ext_list_tmp = ext_list_tmp->next;
+ } while (ext_list_tmp != (*ext_list_head));
+ if (ext->data.physical <
+ ext_list_tmp->prev->data.physical +
+ ext_list_tmp->prev->data.len)
+ /* Overlap */
+ goto out;
+
+ if (ext_list_tmp != *ext_list_head &&
+ ext_list_tmp->data.physical <
+ ext->data.physical + ext->data.len)
+ /* Overlap */
+ goto out;
+ }
+ ext_list_tmp = ext_list_tmp->prev;
+ /* Insert "ext" after "ext_list_tmp" */
+ insert(ext_list_tmp, ext);
+ return 0;
+out:
+ errno = EINVAL;
+ return -1;
+}
+
+/*
+ * insert_exts_group() - Insert a exts_group.
+ *
+ * @ext_group_head: the head of a exts_group list.
+ * @exts_group: the exts_group element which will be inserted.
+ */
+static int insert_exts_group(struct fiemap_extent_group **ext_group_head,
+ struct fiemap_extent_group *exts_group)
+{
+ struct fiemap_extent_group *ext_group_tmp = NULL;
+
+ if (exts_group == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Initialize list */
+ if (*ext_group_head == NULL) {
+ (*ext_group_head) = exts_group;
+ (*ext_group_head)->prev = *ext_group_head;
+ (*ext_group_head)->next = *ext_group_head;
+ return 0;
+ }
+
+ ext_group_tmp = (*ext_group_head)->prev;
+ insert(ext_group_tmp, exts_group);
+
+ return 0;
+}
+
+/*
+ * join_extents() - Find continuous region(exts_group).
+ *
+ * @ext_list_head: the head of the extent list.
+ * @ext_group_head: the head of the target exts_group list.
+ */
+static int join_extents(struct fiemap_extent_list *ext_list_head,
+ struct fiemap_extent_group **ext_group_head)
+{
+ __u64 len = ext_list_head->data.len;
+ struct fiemap_extent_list *ext_list_start = ext_list_head;
+ struct fiemap_extent_list *ext_list_tmp = ext_list_head->next;
+
+ do {
+ struct fiemap_extent_group *ext_group_tmp = NULL;
+
+ /* This extent and previous extent are not continuous,
+ * so, all previous extents are treated as an extent group.
+ */
+ if ((ext_list_tmp->prev->data.logical +
+ ext_list_tmp->prev->data.len)
+ != ext_list_tmp->data.logical) {
+ ext_group_tmp =
+ malloc(sizeof(struct fiemap_extent_group));
+ if (ext_group_tmp == NULL)
+ return -1;
+
+ memset(ext_group_tmp, 0,
+ sizeof(struct fiemap_extent_group));
+ ext_group_tmp->len = len;
+ ext_group_tmp->start = ext_list_start;
+ ext_group_tmp->end = ext_list_tmp->prev;
+
+ if (insert_exts_group(ext_group_head,
+ ext_group_tmp) < 0) {
+ FREE(ext_group_tmp);
+ return -1;
+ }
+ ext_list_start = ext_list_tmp;
+ len = ext_list_tmp->data.len;
+ ext_list_tmp = ext_list_tmp->next;
+ continue;
+ }
+
+ /* This extent and previous extent are continuous,
+ * so, they belong to the same extent group, and we check
+ * if the next extent belongs to the same extent group.
+ */
+ len += ext_list_tmp->data.len;
+ ext_list_tmp = ext_list_tmp->next;
+ } while (ext_list_tmp != ext_list_head->next);
+
+ return 0;
+}
+
+/*
+ * get_file_extents() - Get file's extent list.
+ *
+ * @fd: defrag target file's descriptor.
+ * @ext_list_head: the head of the extent list.
+ */
+static int get_file_extents(int fd, struct fiemap_extent_list **ext_list_head)
+{
+ __u32 i;
+ int ret;
+ int ext_buf_size, fie_buf_size;
+ __u64 pos = 0;
+ struct fiemap *fiemap_buf = NULL;
+ struct fiemap_extent *ext_buf = NULL;
+ struct fiemap_extent_list *ext_list = NULL;
+
+ /* Convert units, in bytes.
+ * Be careful : now, physical block number in extent is 48bit,
+ * and the maximum blocksize for ext4 is 4K(12bit),
+ * so there is no overflow, but in future it may be changed.
+ */
+
+ /* Alloc space for fiemap */
+ ext_buf_size = EXTENT_MAX_COUNT * sizeof(struct fiemap_extent);
+ fie_buf_size = sizeof(struct fiemap) + ext_buf_size;
+
+ fiemap_buf = malloc(fie_buf_size);
+ if (fiemap_buf == NULL)
+ return -1;
+
+ ext_buf = fiemap_buf->fm_extents;
+ memset(fiemap_buf, 0, fie_buf_size);
+ fiemap_buf->fm_length = FIEMAP_MAX_OFFSET;
+ fiemap_buf->fm_flags |= FIEMAP_FLAG_SYNC;
+ fiemap_buf->fm_extent_count = EXTENT_MAX_COUNT;
+
+ do {
+ fiemap_buf->fm_start = pos;
+ memset(ext_buf, 0, ext_buf_size);
+ ret = ioctl(fd, FS_IOC_FIEMAP, fiemap_buf);
+ if (ret < 0 || fiemap_buf->fm_mapped_extents == 0)
+ goto out;
+ for (i = 0; i < fiemap_buf->fm_mapped_extents; i++) {
+ ext_list = NULL;
+ ext_list = malloc(sizeof(struct fiemap_extent_list));
+ if (ext_list == NULL)
+ goto out;
+
+ ext_list->data.physical = ext_buf[i].fe_physical
+ / block_size;
+ ext_list->data.logical = ext_buf[i].fe_logical
+ / block_size;
+ ext_list->data.len = ext_buf[i].fe_length
+ / block_size;
+
+ ret = insert_extent_by_physical(
+ ext_list_head, ext_list);
+ if (ret < 0) {
+ FREE(ext_list);
+ goto out;
+ }
+ }
+ /* Record file's logical offset this time */
+ pos = ext_buf[EXTENT_MAX_COUNT-1].fe_logical +
+ ext_buf[EXTENT_MAX_COUNT-1].fe_length;
+ /*
+ * If fm_extents array has been filled and
+ * there are extents left, continue to cycle.
+ */
+ } while (fiemap_buf->fm_mapped_extents
+ == EXTENT_MAX_COUNT &&
+ !(ext_buf[EXTENT_MAX_COUNT-1].fe_flags
+ & FIEMAP_EXTENT_LAST));
+
+ FREE(fiemap_buf);
+ return 0;
+out:
+ FREE(fiemap_buf);
+ return -1;
+}
+
+/*
+ * get_logical_count() - Get the file logical extents count.
+ *
+ * @logical_list_head: the head of the logical extent list.
+ */
+static int get_logical_count(struct fiemap_extent_list *logical_list_head)
+{
+ int ret = 0;
+ struct fiemap_extent_list *ext_list_tmp = logical_list_head;
+
+ do {
+ ret++;
+ ext_list_tmp = ext_list_tmp->next;
+ } while (ext_list_tmp != logical_list_head);
+
+ return ret;
+}
+
+/*
+ * get_physical_count() - Get the file physical extents count.
+ *
+ * @physical_list_head: the head of the physical extent list.
+ */
+static int get_physical_count(struct fiemap_extent_list *physical_list_head)
+{
+ int ret = 0;
+ struct fiemap_extent_list *ext_list_tmp = physical_list_head;
+
+ do {
+ if ((ext_list_tmp->data.physical + ext_list_tmp->data.len)
+ != ext_list_tmp->next->data.physical) {
+ /* This extent and next extent are not continuous. */
+ ret++;
+ }
+
+ ext_list_tmp = ext_list_tmp->next;
+ } while (ext_list_tmp != physical_list_head);
+
+ return ret;
+}
+
+/*
+ * change_physical_to_logical() - Change list from physical to logical.
+ *
+ * @physical_list_head: the head of physical extent list.
+ * @logical_list_head: the head of logical extent list.
+ */
+static int change_physical_to_logical(
+ struct fiemap_extent_list **physical_list_head,
+ struct fiemap_extent_list **logical_list_head)
+{
+ int ret;
+ struct fiemap_extent_list *ext_list_tmp = *physical_list_head;
+ struct fiemap_extent_list *ext_list_next = ext_list_tmp->next;
+
+ while (1) {
+ if (ext_list_tmp == ext_list_next) {
+ ret = insert_extent_by_logical(
+ logical_list_head, ext_list_tmp);
+ if (ret < 0)
+ return -1;
+
+ *physical_list_head = NULL;
+ break;
+ }
+
+ ext_list_tmp->prev->next = ext_list_tmp->next;
+ ext_list_tmp->next->prev = ext_list_tmp->prev;
+ *physical_list_head = ext_list_next;
+
+ ret = insert_extent_by_logical(
+ logical_list_head, ext_list_tmp);
+ if (ret < 0) {
+ FREE(ext_list_tmp);
+ return -1;
+ }
+ ext_list_tmp = ext_list_next;
+ ext_list_next = ext_list_next->next;
+ }
+
+ return 0;
+}
+
+/* get_file_blocks() - Get total file blocks.
+ *
+ * @ext_list_head: the extent list head of the target file
+ */
+static ext4_fsblk_t get_file_blocks(struct fiemap_extent_list *ext_list_head)
+{
+ ext4_fsblk_t blk_count = 0;
+ struct fiemap_extent_list *ext_list_tmp = ext_list_head;
+
+ do {
+ blk_count += ext_list_tmp->data.len;
+ ext_list_tmp = ext_list_tmp->next;
+ } while (ext_list_tmp != ext_list_head);
+
+ return blk_count;
+}
+
+/*
+ * free_ext() - Free the extent list.
+ *
+ * @ext_list_head: the extent list head of which will be free.
+ */
+static void free_ext(struct fiemap_extent_list *ext_list_head)
+{
+ struct fiemap_extent_list *ext_list_tmp = NULL;
+
+ if (ext_list_head == NULL)
+ return;
+
+ while (ext_list_head->next != ext_list_head) {
+ ext_list_tmp = ext_list_head;
+ ext_list_head->prev->next = ext_list_head->next;
+ ext_list_head->next->prev = ext_list_head->prev;
+ ext_list_head = ext_list_head->next;
+ free(ext_list_tmp);
+ }
+ free(ext_list_head);
+}
+
+/*
+ * free_exts_group() - Free the exts_group.
+ *
+ * @*ext_group_head: the exts_group list head which will be free.
+ */
+static void free_exts_group(struct fiemap_extent_group *ext_group_head)
+{
+ struct fiemap_extent_group *ext_group_tmp = NULL;
+
+ if (ext_group_head == NULL)
+ return;
+
+ while (ext_group_head->next != ext_group_head) {
+ ext_group_tmp = ext_group_head;
+ ext_group_head->prev->next = ext_group_head->next;
+ ext_group_head->next->prev = ext_group_head->prev;
+ ext_group_head = ext_group_head->next;
+ free(ext_group_tmp);
+ }
+ free(ext_group_head);
+}
+
+/*
+ * get_best_count() - Get the file best extents count.
+ *
+ * @block_count: the file's physical block count.
+ */
+static int get_best_count(ext4_fsblk_t block_count)
+{
+ int ret;
+ unsigned int flex_bg_num;
+
+ /* Calcuate best extents count */
+ if (feature_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) {
+ flex_bg_num = 1 << log_groups_per_flex;
+ ret = ((block_count - 1) /
+ ((ext4_fsblk_t)blocks_per_group *
+ flex_bg_num)) + 1;
+ } else
+ ret = ((block_count - 1) / blocks_per_group) + 1;
+
+ return ret;
+}
+
+
+/*
+ * file_statistic() - Get statistic info of the file's fragments.
+ *
+ * @file: the file's name.
+ * @buf: the pointer of the struct stat64.
+ * @flag: file type.
+ * @ftwbuf: the pointer of a struct FTW.
+ */
+static int file_statistic(const char *file, const struct stat64 *buf,
+ int flag EXT2FS_ATTR((unused)),
+ struct FTW *ftwbuf EXT2FS_ATTR((unused)))
+{
+ int fd;
+ int ret;
+ int now_ext_count, best_ext_count = 0, physical_ext_count;
+ int i, j;
+ __u64 size_per_ext = 0;
+ float ratio = 0.0;
+ ext4_fsblk_t blk_count = 0;
+ char msg_buffer[PATH_MAX + 24];
+ struct fiemap_extent_list *physical_list_head = NULL;
+ struct fiemap_extent_list *logical_list_head = NULL;
+
+ defraged_file_count++;
+
+ if (mode_flag & DETAIL) {
+ if (total_count == 1 && regular_count == 1)
+ printf("<File>\n");
+ else {
+ printf("[%u/%u]", defraged_file_count, total_count);
+ fflush(stdout);
+ }
+ }
+ if (lost_found_dir[0] != '\0' &&
+ !memcmp(file, lost_found_dir, strnlen(lost_found_dir, PATH_MAX))) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ STATISTIC_ERR_MSG(NGMSG_LOST_FOUND);
+ }
+ return 0;
+ }
+
+ if (!S_ISREG(buf->st_mode)) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ STATISTIC_ERR_MSG(NGMSG_FILE_UNREG);
+ }
+ return 0;
+ }
+
+ /* Access authority */
+ if (current_uid != ROOT_UID &&
+ buf->st_uid != current_uid) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ STATISTIC_ERR_MSG(
+ "File is not current user's file"
+ " or current user is not root");
+ }
+ return 0;
+ }
+
+ /* Empty file */
+ if (buf->st_size == 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ STATISTIC_ERR_MSG("File size is 0");
+ }
+ return 0;
+ }
+
+ /* Has no blocks */
+ if (buf->st_blocks == 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ STATISTIC_ERR_MSG("File has no blocks");
+ }
+ return 0;
+ }
+
+ fd = open64(file, O_RDONLY);
+ if (fd < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ STATISTIC_ERR_MSG_WITH_ERRNO(NGMSG_FILE_OPEN);
+ }
+ return 0;
+ }
+
+ /* Get file's physical extents */
+ ret = get_file_extents(fd, &physical_list_head);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ STATISTIC_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
+ }
+ goto out;
+ }
+
+ /* Get the count of file's continuous physical region */
+ physical_ext_count = get_physical_count(physical_list_head);
+
+ /* Change list from physical to logical */
+ ret = change_physical_to_logical(&physical_list_head,
+ &logical_list_head);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ STATISTIC_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
+ }
+ goto out;
+ }
+
+ /* Count file fragments before defrag */
+ now_ext_count = get_logical_count(logical_list_head);
+
+ if (current_uid == ROOT_UID) {
+ /* Calculate the size per extent */
+ blk_count = get_file_blocks(logical_list_head);
+
+ best_ext_count = get_best_count(blk_count);
+
+ /* e4defrag rounds size_per_ext up to a block size boundary */
+ size_per_ext = blk_count * (buf->st_blksize / 1024) /
+ now_ext_count;
+
+ ratio = (float)(physical_ext_count - best_ext_count) * 100 /
+ blk_count;
+
+ extents_before_defrag += now_ext_count;
+ extents_after_defrag += best_ext_count;
+ files_block_count += blk_count;
+ }
+
+ if (total_count == 1 && regular_count == 1) {
+ /* File only */
+ if (mode_flag & DETAIL) {
+ int count = 0;
+ struct fiemap_extent_list *ext_list_tmp =
+ logical_list_head;
+
+ /* Print extents info */
+ do {
+ count++;
+ printf("[ext %d]:\tstart %llu:\tlogical "
+ "%llu:\tlen %llu\n", count,
+ ext_list_tmp->data.physical,
+ ext_list_tmp->data.logical,
+ ext_list_tmp->data.len);
+ ext_list_tmp = ext_list_tmp->next;
+ } while (ext_list_tmp != logical_list_head);
+
+ } else {
+ printf("%-40s%10s/%-10s%9s\n",
+ "<File>", "now", "best", "size/ext");
+ if (current_uid == ROOT_UID) {
+ if (strlen(file) > 40)
+ printf("%s\n%50d/%-10d%6llu KB\n",
+ file, now_ext_count,
+ best_ext_count, size_per_ext);
+ else
+ printf("%-40s%10d/%-10d%6llu KB\n",
+ file, now_ext_count,
+ best_ext_count, size_per_ext);
+ } else {
+ if (strlen(file) > 40)
+ printf("%s\n%50d/%-10s%7s\n",
+ file, now_ext_count,
+ "-", "-");
+ else
+ printf("%-40s%10d/%-10s%7s\n",
+ file, now_ext_count,
+ "-", "-");
+ }
+ }
+ succeed_cnt++;
+ goto out;
+ }
+
+ if (mode_flag & DETAIL) {
+ /* Print statistic info */
+ sprintf(msg_buffer, "[%u/%u]%s",
+ defraged_file_count, total_count, file);
+ if (current_uid == ROOT_UID) {
+ if (strlen(msg_buffer) > 40)
+ printf("\033[79;0H\033[K%s\n"
+ "%50d/%-10d%6llu KB\n",
+ msg_buffer, now_ext_count,
+ best_ext_count, size_per_ext);
+ else
+ printf("\033[79;0H\033[K%-40s"
+ "%10d/%-10d%6llu KB\n",
+ msg_buffer, now_ext_count,
+ best_ext_count, size_per_ext);
+ } else {
+ if (strlen(msg_buffer) > 40)
+ printf("\033[79;0H\033[K%s\n%50d/%-10s%7s\n",
+ msg_buffer, now_ext_count,
+ "-", "-");
+ else
+ printf("\033[79;0H\033[K%-40s%10d/%-10s%7s\n",
+ msg_buffer, now_ext_count,
+ "-", "-");
+ }
+ }
+
+ for (i = 0; i < SHOW_FRAG_FILES; i++) {
+ if (ratio >= frag_rank[i].ratio) {
+ for (j = SHOW_FRAG_FILES - 1; j > i; j--) {
+ memset(&frag_rank[j], 0,
+ sizeof(struct frag_statistic_ino));
+ strncpy(frag_rank[j].msg_buffer,
+ frag_rank[j - 1].msg_buffer,
+ strnlen(frag_rank[j - 1].msg_buffer,
+ PATH_MAX));
+ frag_rank[j].now_count =
+ frag_rank[j - 1].now_count;
+ frag_rank[j].best_count =
+ frag_rank[j - 1].best_count;
+ frag_rank[j].size_per_ext =
+ frag_rank[j - 1].size_per_ext;
+ frag_rank[j].ratio =
+ frag_rank[j - 1].ratio;
+ }
+ memset(&frag_rank[i], 0,
+ sizeof(struct frag_statistic_ino));
+ strncpy(frag_rank[i].msg_buffer, file,
+ strnlen(file, PATH_MAX));
+ frag_rank[i].now_count = now_ext_count;
+ frag_rank[i].best_count = best_ext_count;
+ frag_rank[i].size_per_ext = size_per_ext;
+ frag_rank[i].ratio = ratio;
+ break;
+ }
+ }
+
+ succeed_cnt++;
+
+out:
+ close(fd);
+ free_ext(physical_list_head);
+ free_ext(logical_list_head);
+ return 0;
+}
+
+/*
+ * print_progress - Print defrag progress
+ *
+ * @file: file name.
+ * @start: logical offset for defrag target file
+ * @file_size: defrag target filesize
+ */
+static void print_progress(const char *file, loff_t start, loff_t file_size)
+{
+ int percent = (start * 100) / file_size;
+ printf("\033[79;0H\033[K[%u/%u]%s:\t%3d%%",
+ defraged_file_count, total_count, file, min(percent, 100));
+ fflush(stdout);
+
+ return;
+}
+
+/*
+ * call_defrag() - Execute the defrag program.
+ *
+ * @fd: target file descriptor.
+ * @donor_fd: donor file descriptor.
+ * @file: target file name.
+ * @buf: pointer of the struct stat64.
+ * @ext_list_head: head of the extent list.
+ */
+static int call_defrag(int fd, int donor_fd, const char *file,
+ const struct stat64 *buf, struct fiemap_extent_list *ext_list_head)
+{
+ loff_t start = 0;
+ unsigned int page_num;
+ unsigned char *vec = NULL;
+ int defraged_ret = 0;
+ int ret;
+ struct move_extent move_data;
+ struct fiemap_extent_list *ext_list_tmp = NULL;
+
+ memset(&move_data, 0, sizeof(struct move_extent));
+ move_data.donor_fd = donor_fd;
+
+ /* Print defrag progress */
+ print_progress(file, start, buf->st_size);
+
+ ext_list_tmp = ext_list_head;
+ do {
+ move_data.orig_start = ext_list_tmp->data.logical;
+ /* Logical offset of orig and donor should be same */
+ move_data.donor_start = move_data.orig_start;
+ move_data.len = ext_list_tmp->data.len;
+ move_data.moved_len = 0;
+
+ ret = page_in_core(fd, move_data, &vec, &page_num);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ printf("\n");
+ PRINT_ERR_MSG_WITH_ERRNO(
+ "Failed to get file map");
+ } else {
+ printf("\t[ NG ]\n");
+ }
+ return -1;
+ }
+
+ /* EXT4_IOC_MOVE_EXT */
+ defraged_ret =
+ ioctl(fd, EXT4_IOC_MOVE_EXT, &move_data);
+
+ /* Free pages */
+ ret = defrag_fadvise(fd, move_data, vec, page_num);
+ if (vec) {
+ free(vec);
+ vec = NULL;
+ }
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ printf("\n");
+ PRINT_ERR_MSG_WITH_ERRNO(
+ "Failed to free page");
+ } else {
+ printf("\t[ NG ]\n");
+ }
+ return -1;
+ }
+
+ if (defraged_ret < 0) {
+ if (mode_flag & DETAIL) {
+ printf("\n");
+ PRINT_ERR_MSG_WITH_ERRNO(
+ "Failed to defrag with "
+ "EXT4_IOC_MOVE_EXT ioctl");
+ if (errno == ENOTTY)
+ printf("\tAt least 2.6.31-rc1 of "
+ "vanilla kernel is required\n");
+ } else {
+ printf("\t[ NG ]\n");
+ }
+ return -1;
+ }
+ /* Adjust logical offset for next ioctl */
+ move_data.orig_start += move_data.moved_len;
+ move_data.donor_start = move_data.orig_start;
+
+ start = move_data.orig_start * buf->st_blksize;
+
+ /* Print defrag progress */
+ print_progress(file, start, buf->st_size);
+
+ /* End of file */
+ if (start >= buf->st_size)
+ break;
+
+ ext_list_tmp = ext_list_tmp->next;
+ } while (ext_list_tmp != ext_list_head);
+
+ return 0;
+}
+
+/*
+ * file_defrag() - Check file attributes and call ioctl to defrag.
+ *
+ * @file: the file's name.
+ * @buf: the pointer of the struct stat64.
+ * @flag: file type.
+ * @ftwbuf: the pointer of a struct FTW.
+ */
+static int file_defrag(const char *file, const struct stat64 *buf,
+ int flag EXT2FS_ATTR((unused)),
+ struct FTW *ftwbuf EXT2FS_ATTR((unused)))
+{
+ int fd;
+ int donor_fd = -1;
+ int ret;
+ int best;
+ int file_frags_start, file_frags_end;
+ int orig_physical_cnt, donor_physical_cnt = 0;
+ char tmp_inode_name[PATH_MAX + 8];
+ ext4_fsblk_t blk_count = 0;
+ struct fiemap_extent_list *orig_list_physical = NULL;
+ struct fiemap_extent_list *orig_list_logical = NULL;
+ struct fiemap_extent_list *donor_list_physical = NULL;
+ struct fiemap_extent_list *donor_list_logical = NULL;
+ struct fiemap_extent_group *orig_group_head = NULL;
+ struct fiemap_extent_group *orig_group_tmp = NULL;
+
+ defraged_file_count++;
+
+ if (mode_flag & DETAIL) {
+ printf("[%u/%u]", defraged_file_count, total_count);
+ fflush(stdout);
+ }
+
+ if (lost_found_dir[0] != '\0' &&
+ !memcmp(file, lost_found_dir, strnlen(lost_found_dir, PATH_MAX))) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ IN_FTW_PRINT_ERR_MSG(NGMSG_LOST_FOUND);
+ }
+ return 0;
+ }
+
+ if (!S_ISREG(buf->st_mode)) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ IN_FTW_PRINT_ERR_MSG(NGMSG_FILE_UNREG);
+ }
+ return 0;
+ }
+
+ /* Empty file */
+ if (buf->st_size == 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ IN_FTW_PRINT_ERR_MSG("File size is 0");
+ }
+ return 0;
+ }
+
+ /* Has no blocks */
+ if (buf->st_blocks == 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ STATISTIC_ERR_MSG("File has no blocks");
+ }
+ return 0;
+ }
+
+ fd = open64(file, O_RDWR);
+ if (fd < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_OPEN);
+ }
+ return 0;
+ }
+
+ /* Get file's extents */
+ ret = get_file_extents(fd, &orig_list_physical);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
+ }
+ goto out;
+ }
+
+ /* Get the count of file's continuous physical region */
+ orig_physical_cnt = get_physical_count(orig_list_physical);
+
+ /* Change list from physical to logical */
+ ret = change_physical_to_logical(&orig_list_physical,
+ &orig_list_logical);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
+ }
+ goto out;
+ }
+
+ /* Count file fragments before defrag */
+ file_frags_start = get_logical_count(orig_list_logical);
+
+ blk_count = get_file_blocks(orig_list_logical);
+ if (file_check(fd, buf, file, file_frags_start, blk_count) < 0)
+ goto out;
+
+ if (fsync(fd) < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO("Failed to sync(fsync)");
+ }
+ goto out;
+ }
+
+ if (current_uid == ROOT_UID)
+ best = get_best_count(blk_count);
+ else
+ best = 1;
+
+ if (file_frags_start <= best)
+ goto check_improvement;
+
+ /* Combine extents to group */
+ ret = join_extents(orig_list_logical, &orig_group_head);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
+ }
+ goto out;
+ }
+
+ /* Create donor inode */
+ memset(tmp_inode_name, 0, PATH_MAX + 8);
+ sprintf(tmp_inode_name, "%.*s.defrag",
+ (int)strnlen(file, PATH_MAX), file);
+ donor_fd = open64(tmp_inode_name, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
+ if (donor_fd < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ if (errno == EEXIST)
+ PRINT_ERR_MSG_WITH_ERRNO(
+ "File is being defraged by other program");
+ else
+ PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_OPEN);
+ }
+ goto out;
+ }
+
+ /* Unlink donor inode */
+ ret = unlink(tmp_inode_name);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO("Failed to unlink");
+ }
+ goto out;
+ }
+
+ /* Allocate space for donor inode */
+ orig_group_tmp = orig_group_head;
+ do {
+ ret = fallocate64(donor_fd, 0,
+ (loff_t)orig_group_tmp->start->data.logical * block_size,
+ (loff_t)orig_group_tmp->len * block_size);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO("Failed to fallocate");
+ }
+ goto out;
+ }
+
+ orig_group_tmp = orig_group_tmp->next;
+ } while (orig_group_tmp != orig_group_head);
+
+ /* Get donor inode's extents */
+ ret = get_file_extents(donor_fd, &donor_list_physical);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
+ }
+ goto out;
+ }
+
+ /* Calcuate donor inode's continuous physical region */
+ donor_physical_cnt = get_physical_count(donor_list_physical);
+
+ /* Change donor extent list from physical to logical */
+ ret = change_physical_to_logical(&donor_list_physical,
+ &donor_list_logical);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(file);
+ PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
+ }
+ goto out;
+ }
+
+check_improvement:
+ if (mode_flag & DETAIL) {
+ if (file_frags_start != 1)
+ frag_files_before_defrag++;
+
+ extents_before_defrag += file_frags_start;
+ }
+
+ if (file_frags_start <= best ||
+ orig_physical_cnt <= donor_physical_cnt) {
+ printf("\033[79;0H\033[K[%u/%u]%s:\t%3d%%",
+ defraged_file_count, total_count, file, 100);
+ if (mode_flag & DETAIL)
+ printf(" extents: %d -> %d",
+ file_frags_start, file_frags_start);
+
+ printf("\t[ OK ]\n");
+ succeed_cnt++;
+
+ if (file_frags_start != 1)
+ frag_files_after_defrag++;
+
+ extents_after_defrag += file_frags_start;
+ goto out;
+ }
+
+ /* Defrag the file */
+ ret = call_defrag(fd, donor_fd, file, buf, donor_list_logical);
+
+ /* Count file fragments after defrag and print extents info */
+ if (mode_flag & DETAIL) {
+ file_frags_end = file_frag_count(fd);
+ if (file_frags_end < 0) {
+ printf("\n");
+ PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_INFO);
+ goto out;
+ }
+
+ if (file_frags_end != 1)
+ frag_files_after_defrag++;
+
+ extents_after_defrag += file_frags_end;
+
+ if (ret < 0)
+ goto out;
+
+ printf(" extents: %d -> %d",
+ file_frags_start, file_frags_end);
+ fflush(stdout);
+ }
+
+ if (ret < 0)
+ goto out;
+
+ printf("\t[ OK ]\n");
+ fflush(stdout);
+ succeed_cnt++;
+
+out:
+ close(fd);
+ if (donor_fd != -1)
+ close(donor_fd);
+ free_ext(orig_list_physical);
+ free_ext(orig_list_logical);
+ free_ext(donor_list_physical);
+ free_exts_group(orig_group_head);
+ return 0;
+}
+
+/*
+ * main() - Ext4 online defrag.
+ *
+ * @argc: the number of parameter.
+ * @argv[]: the pointer array of parameter.
+ */
+int main(int argc, char *argv[])
+{
+ int opt;
+ int i, j, ret = 0;
+ int flags = FTW_PHYS | FTW_MOUNT;
+ int arg_type = -1;
+ int success_flag = 0;
+ char dir_name[PATH_MAX + 1];
+ char dev_name[PATH_MAX + 1];
+ struct stat64 buf;
+ ext2_filsys fs = NULL;
+
+ /* Parse arguments */
+ if (argc == 1)
+ goto out;
+
+ while ((opt = getopt(argc, argv, "vc")) != EOF) {
+ switch (opt) {
+ case 'v':
+ mode_flag |= DETAIL;
+ break;
+ case 'c':
+ mode_flag |= STATISTIC;
+ break;
+ default:
+ goto out;
+ }
+ }
+
+ if (argc == optind)
+ goto out;
+
+ current_uid = getuid();
+
+ /* Main process */
+ for (i = optind; i < argc; i++) {
+ succeed_cnt = 0;
+ regular_count = 0;
+ total_count = 0;
+ frag_files_before_defrag = 0;
+ frag_files_after_defrag = 0;
+ extents_before_defrag = 0;
+ extents_after_defrag = 0;
+ defraged_file_count = 0;
+ files_block_count = 0;
+ blocks_per_group = 0;
+ feature_incompat = 0;
+ log_groups_per_flex = 0;
+
+ memset(dir_name, 0, PATH_MAX + 1);
+ memset(dev_name, 0, PATH_MAX + 1);
+ memset(lost_found_dir, 0, PATH_MAX + 1);
+ memset(frag_rank, 0,
+ sizeof(struct frag_statistic_ino) * SHOW_FRAG_FILES);
+
+ if ((mode_flag & STATISTIC) && i > optind)
+ printf("\n");
+
+#if BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN
+ PRINT_ERR_MSG("Endian's type is not big/little endian");
+ PRINT_FILE_NAME(argv[i]);
+ continue;
+#endif
+
+ if (lstat64(argv[i], &buf) < 0) {
+ perror(NGMSG_FILE_INFO);
+ PRINT_FILE_NAME(argv[i]);
+ continue;
+ }
+
+ /* Handle i.e. lvm device symlinks */
+ if (S_ISLNK(buf.st_mode)) {
+ struct stat64 buf2;
+
+ if (stat64(argv[i], &buf2) == 0 &&
+ S_ISBLK(buf2.st_mode))
+ buf = buf2;
+ }
+
+ if (S_ISBLK(buf.st_mode)) {
+ /* Block device */
+ strncpy(dev_name, argv[i], strnlen(argv[i], PATH_MAX));
+ if (get_mount_point(argv[i], dir_name, PATH_MAX) < 0)
+ continue;
+ if (lstat64(dir_name, &buf) < 0) {
+ perror(NGMSG_FILE_INFO);
+ PRINT_FILE_NAME(argv[i]);
+ continue;
+ }
+ arg_type = DEVNAME;
+ if (!(mode_flag & STATISTIC))
+ printf("ext4 defragmentation for device(%s)\n",
+ argv[i]);
+ } else if (S_ISDIR(buf.st_mode)) {
+ /* Directory */
+ if (access(argv[i], R_OK) < 0) {
+ perror(argv[i]);
+ continue;
+ }
+ arg_type = DIRNAME;
+ strncpy(dir_name, argv[i], strnlen(argv[i], PATH_MAX));
+ } else if (S_ISREG(buf.st_mode)) {
+ /* Regular file */
+ arg_type = FILENAME;
+ } else {
+ /* Irregular file */
+ PRINT_ERR_MSG(NGMSG_FILE_UNREG);
+ PRINT_FILE_NAME(argv[i]);
+ continue;
+ }
+
+ /* Set blocksize */
+ block_size = buf.st_blksize;
+
+ /* For device case,
+ * filesystem type checked in get_mount_point()
+ */
+ if (arg_type == FILENAME || arg_type == DIRNAME) {
+ if (is_ext4(argv[i], dev_name) < 0)
+ continue;
+ if (realpath(argv[i], dir_name) == NULL) {
+ perror("Couldn't get full path");
+ PRINT_FILE_NAME(argv[i]);
+ continue;
+ }
+ }
+
+ if (current_uid == ROOT_UID) {
+ /* Get super block info */
+ ret = ext2fs_open(dev_name, 0, 0, block_size,
+ unix_io_manager, &fs);
+ if (ret) {
+ if (mode_flag & DETAIL) {
+ perror("Can't get super block info");
+ PRINT_FILE_NAME(argv[i]);
+ }
+ continue;
+ }
+
+ blocks_per_group = fs->super->s_blocks_per_group;
+ feature_incompat = fs->super->s_feature_incompat;
+ log_groups_per_flex = fs->super->s_log_groups_per_flex;
+
+ ext2fs_close(fs);
+ }
+
+ switch (arg_type) {
+ int mount_dir_len = 0;
+
+ case DIRNAME:
+ if (!(mode_flag & STATISTIC))
+ printf("ext4 defragmentation "
+ "for directory(%s)\n", argv[i]);
+
+ mount_dir_len = strnlen(lost_found_dir, PATH_MAX);
+
+ strncat(lost_found_dir, "/lost+found",
+ PATH_MAX - strnlen(lost_found_dir, PATH_MAX));
+
+ /* Not the case("e4defrag mount_piont_dir") */
+ if (dir_name[mount_dir_len] != '\0') {
+ /*
+ * "e4defrag mount_piont_dir/lost+found"
+ * or "e4defrag mount_piont_dir/lost+found/"
+ */
+ if (strncmp(lost_found_dir, dir_name,
+ strnlen(lost_found_dir,
+ PATH_MAX)) == 0 &&
+ (dir_name[strnlen(lost_found_dir,
+ PATH_MAX)] == '\0' ||
+ dir_name[strnlen(lost_found_dir,
+ PATH_MAX)] == '/')) {
+ PRINT_ERR_MSG(NGMSG_LOST_FOUND);
+ PRINT_FILE_NAME(argv[i]);
+ continue;
+ }
+
+ /* "e4defrag mount_piont_dir/else_dir" */
+ memset(lost_found_dir, 0, PATH_MAX + 1);
+ }
+ case DEVNAME:
+ if (arg_type == DEVNAME) {
+ strncpy(lost_found_dir, dir_name,
+ strnlen(dir_name, PATH_MAX));
+ strncat(lost_found_dir, "/lost+found/",
+ PATH_MAX - strnlen(lost_found_dir,
+ PATH_MAX));
+ }
+
+ nftw64(dir_name, calc_entry_counts, FTW_OPEN_FD, flags);
+
+ if (mode_flag & STATISTIC) {
+ if (mode_flag & DETAIL)
+ printf("%-40s%10s/%-10s%9s\n",
+ "<File>", "now", "best", "size/ext");
+
+ if (!(mode_flag & DETAIL) &&
+ current_uid != ROOT_UID) {
+ printf(" Done.\n");
+ success_flag = 1;
+ continue;
+ }
+
+ nftw64(dir_name, file_statistic,
+ FTW_OPEN_FD, flags);
+
+ if (succeed_cnt != 0 &&
+ current_uid == ROOT_UID) {
+ if (mode_flag & DETAIL)
+ printf("\n");
+ printf("%-40s%10s/%-10s%9s\n",
+ "<Fragmented files>", "now",
+ "best", "size/ext");
+ for (j = 0; j < SHOW_FRAG_FILES; j++) {
+ if (strlen(frag_rank[j].
+ msg_buffer) > 37) {
+ printf("%d. %s\n%50d/"
+ "%-10d%6llu KB\n",
+ j + 1,
+ frag_rank[j].msg_buffer,
+ frag_rank[j].now_count,
+ frag_rank[j].best_count,
+ frag_rank[j].
+ size_per_ext);
+ } else if (strlen(frag_rank[j].
+ msg_buffer) > 0) {
+ printf("%d. %-37s%10d/"
+ "%-10d%6llu KB\n",
+ j + 1,
+ frag_rank[j].msg_buffer,
+ frag_rank[j].now_count,
+ frag_rank[j].best_count,
+ frag_rank[j].
+ size_per_ext);
+ } else
+ break;
+ }
+ }
+ break;
+ }
+ /* File tree walk */
+ nftw64(dir_name, file_defrag, FTW_OPEN_FD, flags);
+ printf("\n\tSuccess:\t\t\t[ %u/%u ]\n", succeed_cnt,
+ total_count);
+ printf("\tFailure:\t\t\t[ %u/%u ]\n",
+ total_count - succeed_cnt, total_count);
+ if (mode_flag & DETAIL) {
+ printf("\tTotal extents:\t\t\t%4d->%d\n",
+ extents_before_defrag,
+ extents_after_defrag);
+ printf("\tFragmented percentage:\t\t"
+ "%3llu%%->%llu%%\n",
+ !regular_count ? 0 :
+ ((unsigned long long)
+ frag_files_before_defrag * 100) /
+ regular_count,
+ !regular_count ? 0 :
+ ((unsigned long long)
+ frag_files_after_defrag * 100) /
+ regular_count);
+ }
+ break;
+ case FILENAME:
+ total_count = 1;
+ regular_count = 1;
+ strncat(lost_found_dir, "/lost+found/",
+ PATH_MAX - strnlen(lost_found_dir,
+ PATH_MAX));
+ if (strncmp(lost_found_dir, dir_name,
+ strnlen(lost_found_dir,
+ PATH_MAX)) == 0) {
+ PRINT_ERR_MSG(NGMSG_LOST_FOUND);
+ PRINT_FILE_NAME(argv[i]);
+ continue;
+ }
+
+ if (mode_flag & STATISTIC) {
+ file_statistic(argv[i], &buf, FTW_F, NULL);
+ break;
+ } else
+ printf("ext4 defragmentation for %s\n",
+ argv[i]);
+ /* Defrag single file process */
+ file_defrag(argv[i], &buf, FTW_F, NULL);
+ if (succeed_cnt != 0)
+ printf(" Success:\t\t\t[1/1]\n");
+ else
+ printf(" Success:\t\t\t[0/1]\n");
+
+ break;
+ }
+
+ if (succeed_cnt != 0)
+ success_flag = 1;
+ if (mode_flag & STATISTIC) {
+ if (current_uid != ROOT_UID) {
+ printf(" Done.\n");
+ continue;
+ }
+
+ if (!succeed_cnt) {
+ if (mode_flag & DETAIL)
+ printf("\n");
+
+ if (arg_type == DEVNAME)
+ printf(" In this device(%s), "
+ "none can be defragmented.\n", argv[i]);
+ else if (arg_type == DIRNAME)
+ printf(" In this directory(%s), "
+ "none can be defragmented.\n", argv[i]);
+ else
+ printf(" This file(%s) "
+ "can't be defragmented.\n", argv[i]);
+ } else {
+ float files_ratio = 0.0;
+ float score = 0.0;
+ __u64 size_per_ext = files_block_count *
+ (buf.st_blksize / 1024) /
+ extents_before_defrag;
+ files_ratio = (float)(extents_before_defrag -
+ extents_after_defrag) *
+ 100 / files_block_count;
+ score = CALC_SCORE(files_ratio);
+ printf("\n Total/best extents\t\t\t\t%d/%d\n"
+ " Average size per extent"
+ "\t\t\t%llu KB\n"
+ " Fragmentation score\t\t\t\t%.0f\n",
+ extents_before_defrag,
+ extents_after_defrag,
+ size_per_ext, score);
+ printf(" [0-30 no problem:"
+ " 31-55 a little bit fragmented:"
+ " 56- needs defrag]\n");
+
+ if (arg_type == DEVNAME)
+ printf(" This device (%s) ", argv[i]);
+ else if (arg_type == DIRNAME)
+ printf(" This directory (%s) ",
+ argv[i]);
+ else
+ printf(" This file (%s) ", argv[i]);
+
+ if (score > BOUND_SCORE)
+ printf("needs defragmentation.\n");
+ else
+ printf("does not need "
+ "defragmentation.\n");
+ }
+ printf(" Done.\n");
+ }
+
+ }
+
+ if (success_flag)
+ return 0;
+
+ exit(1);
+
+out:
+ printf(MSG_USAGE);
+ exit(1);
+}
+
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/ext4.5.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/ext4.5.in
new file mode 100644
index 0000000..98494ec
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/ext4.5.in
@@ -0,0 +1,257 @@
+.\" -*- nroff -*-
+.\" Copyright 1993, 1994, 1995 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH EXT4 5 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+ext2 \- the second extended file system
+.br
+ext2 \- the third extended file system
+.br
+ext4 \- the fourth extended file system
+.SH DESCRIPTION
+The second, third, and fourth extended file systems, or ext2, ext3, and
+ext4 as they are commonly known, are Linux file systems that have
+historically been the default file system for many Linux distributions.
+They are general purpose file systems that have been designed for
+extensibility and backwards compatibility. In particular, file systems
+previously intended for use with the ext2 and ext3 file systems can be
+mounted using the ext4 file system driver, and indeed in many modern
+Linux distributions, the ext4 file system driver has been configured
+handle mount requests for ext2 and ext3 file systems.
+.SH FILE SYSTEM FEATURES
+A file system formated for ext2, ext3, or ext4 can be have some
+collection of the follow file system feature flags enabled. Some of
+these features are not supported by all implementations of the ext2,
+ext3, and ext4 file system drivers, depending on Linux kernel version in
+use. On other operating systems, such as the GNU/HURD or FreeBSD, only
+a very restrictive set of file system features may be supported in their
+implementations of ext2.
+.RS 1.2i
+.TP
+.B 64bit
+.br
+Enables the file system to be larger than 2^32 blocks. This feature is set
+automatically, as needed, but it can be useful to specify this feature
+explicitly if the file system might need to be resized larger than 2^32
+blocks, even if it was smaller than that threshold when it was
+originally created. Note that some older kernels and older versions
+of e2fsprogs will not support file systems with this ext4 feature enabled.
+.TP
+.B bigalloc
+.br
+This ext4 feature enables clustered block allocation, so that the unit of
+allocation is a power of two number of blocks. That is, each bit in the
+what had traditionally been known as the block allocation bitmap now
+indicates whether a cluster is in use or not, where a cluster is by
+default composed of 16 blocks. This feature can decrease the time
+spent on doing block allocation and brings smaller fragmentation, especially
+for large files. The size can be specified using the
+.B \-C option.
+.IP
+.B Warning:
+The bigalloc feature is still under development, and may not be fully
+supported with your kernel or may have various bugs. Please see the web
+page http://ext4.wiki.kernel.org/index.php/Bigalloc for details.
+May clash with delayed allocation (see
+.BR nodelalloc mount option).
+.IP
+This feature requires that the
+.B extent
+features be enabled.
+.TP
+.B dir_index
+.br
+Use hashed b-trees to speed up name lookups in large directories. This
+feature is supported by ext3 and ext4 file systems, and is ignored by
+ext2 file systems.
+.TP
+.B dir_nlink
+.br
+This ext4 feature allows more than 65000 subdirectories per directory.
+.TP
+.B extent
+.br
+This ext4 feature allows the mapping of logical block numbers for a
+particular inode to physical blocks on the storage device to be stored
+using an extent tree, which is a more efficient data structure than the
+traditional indirect block scheme used by the ext2 and ext3 file
+systems. The use of the extent tree decreases metadata block overhead,
+improves file system performance, and decreases the needed to run
+.BR e2fsck (8)
+on the file system.
+(Note: both
+.B extent
+and
+.B extents
+are accepted as valid names for this feature for
+historical/backwards compatibility reasons.)
+.TP
+.B extra_isize
+.br
+This ext4 feature reserves a specific amount of space in each inode for
+extended metadata such as nanosecond timestamps and file creation time,
+even if the current kernel does not current need to reserve this much
+space. Without this feature, the kernel will reserve the amount of
+space for features currently it currently needs, and the rest may be
+consumed by extended attributes.
+
+For this feature to be useful the inode size must be 256 bytes in size
+or larger.
+.TP
+.B ext_attr
+.br
+This feature enables the use of extended attributes. This feature is
+supported by ext2, ext3, and ext4.
+.TP
+.B filetype
+.br
+This feature enables the storage file type information in directory
+entries. This feature is supported by ext2, ext3, and ext4.
+.TP
+.TP
+.B flex_bg
+.br
+This ext4 feature allows the per-block group metadata (allocation
+bitmaps
+and inode tables)
+to be placed anywhere on the storage media. In addition,
+.B mke2fs
+will place the per-block group metadata together starting at the first
+block group of each "flex_bg group". The size of the flex_bg group
+can be specified using the
+.B \-G
+option.
+.TP
+.B has_journal
+.br
+Create a journal to ensure filesystem consistency even across unclean
+shutdowns. Setting the filesystem feature is equivalent to using the
+.B \-j
+option. This feature is supported by ext3 and ext4, and ignored by the
+ext2 file system driver.
+.TP
+.B huge_file
+.br
+This ext4 feature allows files to be larger than 2 terabytes in size.
+.TP
+.B journal_dev
+.br
+This feature is enabled on the superblock found on an external journal
+device. The block size for the external journal must be the same as the
+file system which uses it.
+.IP
+The external journal device can be used by a file system by specifying
+the
+.B \-J
+.BR device= <external-device>
+option to
+.BR mke2fs (8)
+or
+.BR tune2fs(8).
+.TP
+.B large_file
+.br
+This feature flag is set automatically by modern kernels when a file
+larger than 2 gigabytes is created. Very old kernels could not
+handle large files, so this feature flag was used to prohibit those
+kernels from mounting file systems that they could not understand.
+.\" .TP
+.\" .B metadata_csum
+.\" .br
+.\" This ext4 feature enables metadata checksumming. This feature stores
+.\" checksums for all of the filesystem metadata (superblock, group
+.\" descriptor blocks, inode and block bitmaps, directories, and
+.\" extent tree blocks). The checksum algorithm used for the metadata
+.\" blocks is different than the one used for group descriptors with the
+.\" .B uninit_bg
+.\" feature, these two features are incompatible and
+.\" .B metadata_csum
+.\" will be used preferentially instead of
+.\" .BR uninit_bg .
+.\" .br
+.\" .B Future feature, available in e2fsprogs 1.43-WIP
+.TP
+.B meta_bg
+.br
+This ext4 feature allows file systems to be resized on-line without explicitly
+needing to reserve space for growth in the size of the block group
+descriptors. This scheme is also used to resize file systems which are
+larger than 2^32 blocks. It is not recommended that this feature be set
+when a file system is created, since this alternate method of storing
+the block group descriptor will slow down the time needed to mount the
+file system, and newer kernels can automatically set this feature as
+necessary when doing an online resize and no more reserved space is
+available in the resize inode.
+.TP
+.B mmp
+.br
+This ext4 feature provides multiple mount protection (MMP). MMP helps to
+protect the filesystem from being multiply mounted and is useful in
+shared storage environments.
+@QUOTA_MAN_COMMENT@.TP
+@QUOTA_MAN_COMMENT@.B quota
+@QUOTA_MAN_COMMENT@.br
+@QUOTA_MAN_COMMENT@Create quota inodes (inode #3 for userquota and inode
+@QUOTA_MAN_COMMENT@#4 for group quota) and set them in the superblock.
+@QUOTA_MAN_COMMENT@With this feature, the quotas will be enabled
+@QUOTA_MAN_COMMENT@automatically when the filesystem is mounted.
+@QUOTA_MAN_COMMENT@.IP
+@QUOTA_MAN_COMMENT@Causes the quota files (i.e., user.quota and
+@QUOTA_MAN_COMMENT@group.quota which existed
+@QUOTA_MAN_COMMENT@in the older quota design) to be hidden inodes.
+@QUOTA_MAN_COMMENT@.IP
+@QUOTA_MAN_COMMENT@.B Warning:
+@QUOTA_MAN_COMMENT@The quota feature is still under development,
+@QUOTA_MAN_COMMENT@and may not be fully supported with your kernel
+@QUOTA_MAN_COMMENT@or may have various bugs. Please
+@QUOTA_MAN_COMMENT@see https://ext4.wiki.kernel.org/index.php/Quota
+@QUOTA_MAN_COMMENT@for more details.
+.TP
+.B resize_inode
+.br
+This file system feature indicates that space has been reserved so
+the block group descriptor table can be extended by the file system is
+resized while the file system is mounted. The online resize operation
+is carried out by the kernel, triggered, by
+.BR resize2fs (8).
+By default
+.B mke2fs
+will attempt to reserve enough space so that the
+filesystem may grow to 1024 times its initial size. This can be changed
+using the
+.B resize
+extended option.
+.IP
+This feature requires that the
+.B sparse_super
+feature be enabled.
+.TP
+.B sparse_super
+.br
+This file system feature is set on all modern ext2, ext3, and ext4 file
+system. It indicates that backup copies of the superblock and block
+group descriptors be present only on a few block groups, and not all of
+them.
+.TP
+.B uninit_bg
+.br
+This ext4 file system feature indicates that the block group descriptors
+will be protected using checksums, making it safe for
+.BR mke2fs (8)
+to create a file system without initializing all of the block groups.
+The kernel will keep a high watermark of unused inodes, and initialize
+inode tables and block lazily. This feature speeds up the time to check
+the file system using
+.BR e2fsck (8),
+and it also speeds up the time required for
+.BR mke2fs (8)
+to create the file system.
+.RE
+.SH SEE ALSO
+.BR mke2fs (8),
+.BR mke2fs.conf (5),
+.BR e2fsck (8),
+.BR dumpe2fs (8),
+.BR tune2fs (8),
+.BR debugfs (8)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/filefrag.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/filefrag.8.in
new file mode 100644
index 0000000..a6d7b27
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/filefrag.8.in
@@ -0,0 +1,62 @@
+.\" -*- nroff -*-
+.TH FILEFRAG 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+filefrag \- report on file fragmentation
+.SH SYNOPSIS
+.B filefrag
+[
+.BI \-b blocksize
+]
+[
+.B \-BeksvxX
+]
+[
+.I files...
+]
+.SH DESCRIPTION
+.B filefrag
+reports on how badly fragmented a particular file might be. It makes
+allowances for indirect blocks for ext2 and ext3 filesystems, but can be
+used on files for any filesystem.
+.PP
+The
+.B filefrag
+program initially attempts to get the
+extent information using FIEMAP ioctl which is more efficient and faster.
+If FIEMAP is not supported then filefrag will fall back to using FIBMAP.
+.SH OPTIONS
+.TP
+.B \-B
+Force the use of the older FIBMAP ioctl instead of the FIEMAP ioctl for
+testing purposes.
+.TP
+.BI \-b blocksize
+Use
+.I blocksize
+in bytes for output instead of the filesystem blocksize.
+For compatibility with earlier versions of
+.BR filefrag ,
+if
+.I blocksize
+is unspecified it defaults to 1024 bytes.
+.TP
+.B \-e
+Print output in extent format, even for block-mapped files.
+.TP
+.BI \-k
+Use 1024\-byte blocksize for output (identical to '\-b 1024').
+.TP
+.B \-s
+Sync the file before requesting the mapping.
+.TP
+.B \-v
+Be verbose when checking for file fragmentation.
+.TP
+.B \-x
+Display mapping of extended attributes.
+.TP
+.B \-X
+Display extent block numbers in hexadecimal format.
+.SH AUTHOR
+.B filefrag
+was written by Theodore Ts'o <tytso@mit.edu>.
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/filefrag.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/filefrag.c
new file mode 100644
index 0000000..a050a22
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/filefrag.c
@@ -0,0 +1,525 @@
+/*
+ * filefrag.c -- report if a particular file is fragmented
+ *
+ * Copyright 2003 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "config.h"
+#ifndef __linux__
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(void) {
+ fputs("This program is only supported on Linux!\n", stderr);
+ exit(EXIT_FAILURE);
+}
+#else
+#define _LARGEFILE64_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/ioctl.h>
+#include <linux/fd.h>
+#include <ext2fs/ext2fs.h>
+#include <ext2fs/ext2_types.h>
+#include <ext2fs/fiemap.h>
+
+int verbose = 0;
+int blocksize; /* Use specified blocksize (default 1kB) */
+int sync_file = 0; /* fsync file before getting the mapping */
+int xattr_map = 0; /* get xattr mapping */
+int force_bmap; /* force use of FIBMAP instead of FIEMAP */
+int force_extent; /* print output in extent format always */
+int logical_width = 8;
+int physical_width = 10;
+const char *ext_fmt = "%4d: %*llu..%*llu: %*llu..%*llu: %6llu: %s\n";
+const char *hex_fmt = "%4d: %*llx..%*llx: %*llx..%*llx: %6llx: %s\n";
+
+#define FILEFRAG_FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR)
+
+#define FIBMAP _IO(0x00, 1) /* bmap access */
+#define FIGETBSZ _IO(0x00, 2) /* get the block size used for bmap */
+
+#define LUSTRE_SUPER_MAGIC 0x0BD00BD0
+
+#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
+#define EXT3_IOC_GETFLAGS _IOR('f', 1, long)
+
+static int int_log2(int arg)
+{
+ int l = 0;
+
+ arg >>= 1;
+ while (arg) {
+ l++;
+ arg >>= 1;
+ }
+ return l;
+}
+
+static int int_log10(unsigned long long arg)
+{
+ int l = 0;
+
+ arg = arg / 10;
+ while (arg) {
+ l++;
+ arg = arg / 10;
+ }
+ return l;
+}
+
+static unsigned int div_ceil(unsigned int a, unsigned int b)
+{
+ if (!a)
+ return 0;
+ return ((a - 1) / b) + 1;
+}
+
+static int get_bmap(int fd, unsigned long block, unsigned long *phy_blk)
+{
+ int ret;
+ unsigned int b;
+
+ b = block;
+ ret = ioctl(fd, FIBMAP, &b); /* FIBMAP takes pointer to integer */
+ if (ret < 0) {
+ if (errno == EPERM) {
+ fprintf(stderr, "No permission to use FIBMAP ioctl; "
+ "must have root privileges\n");
+ }
+ }
+ *phy_blk = b;
+
+ return ret;
+}
+
+static void print_extent_header(void)
+{
+ printf(" ext: %*s %*s length: %*s flags:\n",
+ logical_width * 2 + 3,
+ "logical_offset:",
+ physical_width * 2 + 3, "physical_offset:",
+ physical_width + 1,
+ "expected:");
+}
+
+static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex,
+ unsigned long long expected, int blk_shift,
+ ext2fs_struct_stat *st)
+{
+ unsigned long long physical_blk;
+ unsigned long long logical_blk;
+ unsigned long long ext_len;
+ unsigned long long ext_blks;
+ char flags[256] = "";
+
+ /* For inline data all offsets should be in bytes, not blocks */
+ if (fm_extent->fe_flags & FIEMAP_EXTENT_DATA_INLINE)
+ blk_shift = 0;
+
+ ext_len = fm_extent->fe_length >> blk_shift;
+ ext_blks = (fm_extent->fe_length - 1) >> blk_shift;
+ logical_blk = fm_extent->fe_logical >> blk_shift;
+ physical_blk = fm_extent->fe_physical >> blk_shift;
+
+ if (expected)
+ sprintf(flags, ext_fmt == hex_fmt ? "%*llx: " : "%*llu: ",
+ physical_width, expected >> blk_shift);
+ else
+ sprintf(flags, "%.*s ", physical_width, " ");
+
+ if (fm_extent->fe_flags & FIEMAP_EXTENT_UNKNOWN)
+ strcat(flags, "unknown,");
+ if (fm_extent->fe_flags & FIEMAP_EXTENT_DELALLOC)
+ strcat(flags, "delalloc,");
+ if (fm_extent->fe_flags & FIEMAP_EXTENT_DATA_ENCRYPTED)
+ strcat(flags, "encrypted,");
+ if (fm_extent->fe_flags & FIEMAP_EXTENT_NOT_ALIGNED)
+ strcat(flags, "not_aligned,");
+ if (fm_extent->fe_flags & FIEMAP_EXTENT_DATA_INLINE)
+ strcat(flags, "inline,");
+ if (fm_extent->fe_flags & FIEMAP_EXTENT_DATA_TAIL)
+ strcat(flags, "tail_packed,");
+ if (fm_extent->fe_flags & FIEMAP_EXTENT_UNWRITTEN)
+ strcat(flags, "unwritten,");
+ if (fm_extent->fe_flags & FIEMAP_EXTENT_MERGED)
+ strcat(flags, "merged,");
+
+ if (fm_extent->fe_logical + fm_extent->fe_length >= (__u64) st->st_size)
+ strcat(flags, "eof,");
+
+ /* Remove trailing comma, if any */
+ if (flags[0])
+ flags[strlen(flags) - 1] = '\0';
+
+ printf(ext_fmt, cur_ex, logical_width, logical_blk,
+ logical_width, logical_blk + ext_blks,
+ physical_width, physical_blk,
+ physical_width, physical_blk + ext_blks,
+ ext_len, flags);
+}
+
+static int filefrag_fiemap(int fd, int blk_shift, int *num_extents,
+ ext2fs_struct_stat *st)
+{
+ char buf[16384];
+ struct fiemap *fiemap = (struct fiemap *)buf;
+ struct fiemap_extent *fm_ext = &fiemap->fm_extents[0];
+ int count = (sizeof(buf) - sizeof(*fiemap)) /
+ sizeof(struct fiemap_extent);
+ unsigned long long expected = 0;
+ unsigned long flags = 0;
+ unsigned int i;
+ static int fiemap_incompat_printed;
+ int fiemap_header_printed = 0;
+ int tot_extents = 0, n = 0;
+ int last = 0;
+ int rc;
+
+ memset(fiemap, 0, sizeof(struct fiemap));
+
+ if (sync_file)
+ flags |= FIEMAP_FLAG_SYNC;
+
+ if (xattr_map)
+ flags |= FIEMAP_FLAG_XATTR;
+
+ do {
+ fiemap->fm_length = ~0ULL;
+ fiemap->fm_flags = flags;
+ fiemap->fm_extent_count = count;
+ rc = ioctl(fd, FS_IOC_FIEMAP, (unsigned long) fiemap);
+ if (rc < 0) {
+ if (errno == EBADR && fiemap_incompat_printed == 0) {
+ printf("FIEMAP failed with unsupported "
+ "flags %x\n", fiemap->fm_flags);
+ fiemap_incompat_printed = 1;
+ }
+ return rc;
+ }
+
+ /* If 0 extents are returned, then more ioctls are not needed */
+ if (fiemap->fm_mapped_extents == 0)
+ break;
+
+ if (verbose && !fiemap_header_printed) {
+ print_extent_header();
+ fiemap_header_printed = 1;
+ }
+
+ for (i = 0; i < fiemap->fm_mapped_extents; i++) {
+ if (fm_ext[i].fe_logical != 0 &&
+ fm_ext[i].fe_physical != expected) {
+ tot_extents++;
+ } else {
+ expected = 0;
+ if (!tot_extents)
+ tot_extents = 1;
+ }
+ if (verbose)
+ print_extent_info(&fm_ext[i], n, expected,
+ blk_shift, st);
+
+ expected = fm_ext[i].fe_physical + fm_ext[i].fe_length;
+ if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
+ last = 1;
+ n++;
+ }
+
+ fiemap->fm_start = (fm_ext[i - 1].fe_logical +
+ fm_ext[i - 1].fe_length);
+ } while (last == 0);
+
+ *num_extents = tot_extents;
+
+ return 0;
+}
+
+#define EXT2_DIRECT 12
+
+static int filefrag_fibmap(int fd, int blk_shift, int *num_extents,
+ ext2fs_struct_stat *st,
+ unsigned long numblocks, int is_ext2)
+{
+ struct fiemap_extent fm_ext;
+ unsigned long i, last_block;
+ unsigned long long logical;
+ /* Blocks per indirect block */
+ const long bpib = st->st_blksize / 4;
+ int count;
+
+ if (force_extent) {
+ memset(&fm_ext, 0, sizeof(fm_ext));
+ fm_ext.fe_flags = FIEMAP_EXTENT_MERGED;
+ }
+
+ if (sync_file)
+ fsync(fd);
+
+ for (i = 0, logical = 0, *num_extents = 0, count = last_block = 0;
+ i < numblocks;
+ i++, logical += st->st_blksize) {
+ unsigned long block = 0;
+ int rc;
+
+ if (is_ext2 && last_block) {
+ if (((i - EXT2_DIRECT) % bpib) == 0)
+ last_block++;
+ if (((i - EXT2_DIRECT - bpib) % (bpib * bpib)) == 0)
+ last_block++;
+ if (((i - EXT2_DIRECT - bpib - bpib * bpib) %
+ (((unsigned long long)bpib) * bpib * bpib)) == 0)
+ last_block++;
+ }
+ rc = get_bmap(fd, i, &block);
+ if (rc < 0)
+ return rc;
+ if (block == 0)
+ continue;
+ if (*num_extents == 0) {
+ (*num_extents)++;
+ if (force_extent) {
+ print_extent_header();
+ fm_ext.fe_physical = block * st->st_blksize;
+ }
+ }
+ count++;
+ if (force_extent && last_block != 0 &&
+ (block != last_block + 1 ||
+ fm_ext.fe_logical + fm_ext.fe_length != logical)) {
+ print_extent_info(&fm_ext, *num_extents - 1,
+ (last_block + 1) * st->st_blksize,
+ blk_shift, st);
+ fm_ext.fe_logical = logical;
+ fm_ext.fe_physical = block * st->st_blksize;
+ fm_ext.fe_length = 0;
+ (*num_extents)++;
+ } else if (verbose && last_block && (block != last_block + 1)) {
+ printf("Discontinuity: Block %ld is at %lu (was %lu)\n",
+ i, block, last_block + 1);
+ (*num_extents)++;
+ }
+ fm_ext.fe_length += st->st_blksize;
+ last_block = block;
+ }
+
+ if (force_extent)
+ print_extent_info(&fm_ext, *num_extents - 1,
+ last_block * st->st_blksize, blk_shift, st);
+
+ return count;
+}
+
+static void frag_report(const char *filename)
+{
+ static struct statfs fsinfo;
+ ext2fs_struct_stat st;
+ int blk_shift;
+ long fd;
+ unsigned long numblocks;
+ int data_blocks_per_cyl = 1;
+ int num_extents = 1, expected = ~0;
+ int is_ext2 = 0;
+ static dev_t last_device;
+ unsigned int flags;
+ int width;
+
+#if defined(HAVE_OPEN64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
+ fd = open64(filename, O_RDONLY);
+#else
+ fd = open(filename, O_RDONLY);
+#endif
+ if (fd < 0) {
+ perror("open");
+ return;
+ }
+
+#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
+ if (fstat64(fd, &st) < 0) {
+#else
+ if (fstat(fd, &st) < 0) {
+#endif
+ close(fd);
+ perror("stat");
+ return;
+ }
+
+ if (last_device != st.st_dev) {
+ if (fstatfs(fd, &fsinfo) < 0) {
+ close(fd);
+ perror("fstatfs");
+ return;
+ }
+ if (verbose)
+ printf("Filesystem type is: %lx\n",
+ (unsigned long) fsinfo.f_type);
+ }
+ st.st_blksize = fsinfo.f_bsize;
+ if (ioctl(fd, EXT3_IOC_GETFLAGS, &flags) < 0)
+ flags = 0;
+ if (!(flags & EXT4_EXTENTS_FL) &&
+ ((fsinfo.f_type == 0xef51) || (fsinfo.f_type == 0xef52) ||
+ (fsinfo.f_type == 0xef53)))
+ is_ext2++;
+
+ if (is_ext2) {
+ long cylgroups = div_ceil(fsinfo.f_blocks, fsinfo.f_bsize * 8);
+
+ if (verbose && last_device != st.st_dev)
+ printf("Filesystem cylinder groups approximately %ld\n",
+ cylgroups);
+
+ data_blocks_per_cyl = fsinfo.f_bsize * 8 -
+ (fsinfo.f_files / 8 / cylgroups) - 3;
+ }
+ last_device = st.st_dev;
+
+ width = int_log10(fsinfo.f_blocks);
+ if (width > physical_width)
+ physical_width = width;
+
+ numblocks = (st.st_size + fsinfo.f_bsize - 1) / fsinfo.f_bsize;
+ if (blocksize != 0)
+ blk_shift = int_log2(blocksize);
+ else
+ blk_shift = int_log2(fsinfo.f_bsize);
+
+ width = int_log10(numblocks);
+ if (width > logical_width)
+ logical_width = width;
+ if (verbose)
+ printf("File size of %s is %llu (%lu block%s of %d bytes)\n",
+ filename, (unsigned long long)st.st_size,
+ numblocks * fsinfo.f_bsize >> blk_shift,
+ numblocks == 1 ? "" : "s", 1 << blk_shift);
+
+ if (force_bmap ||
+ filefrag_fiemap(fd, blk_shift, &num_extents, &st) != 0) {
+ expected = filefrag_fibmap(fd, blk_shift, &num_extents,
+ &st, numblocks, is_ext2);
+ if (expected < 0) {
+ if (errno == EINVAL || errno == ENOTTY) {
+ fprintf(stderr, "%s: FIBMAP unsupported\n",
+ filename);
+ } else if (errno != EPERM) {
+ fprintf(stderr, "%s: FIBMAP error: %s",
+ filename, strerror(errno));
+ }
+ goto out_close;
+ }
+ expected = expected / data_blocks_per_cyl + 1;
+ }
+
+ if (num_extents == 1)
+ printf("%s: 1 extent found", filename);
+ else
+ printf("%s: %d extents found", filename, num_extents);
+ /* count, and thus expected, only set for indirect FIBMAP'd files */
+ if (is_ext2 && expected && expected < num_extents)
+ printf(", perfection would be %d extent%s\n", expected,
+ (expected > 1) ? "s" : "");
+ else
+ fputc('\n', stdout);
+out_close:
+ close(fd);
+}
+
+static void usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s [-b{blocksize}] [-BeklsvxX] file ...\n",
+ progname);
+ exit(1);
+}
+
+int main(int argc, char**argv)
+{
+ char **cpp;
+ int c;
+
+ while ((c = getopt(argc, argv, "Bb::eksvxX")) != EOF)
+ switch (c) {
+ case 'B':
+ force_bmap++;
+ break;
+ case 'b':
+ if (optarg) {
+ char *end;
+ blocksize = strtoul(optarg, &end, 0);
+ if (end) {
+ switch (end[0]) {
+ case 'g':
+ case 'G':
+ blocksize *= 1024;
+ /* no break */
+ case 'm':
+ case 'M':
+ blocksize *= 1024;
+ /* no break */
+ case 'k':
+ case 'K':
+ blocksize *= 1024;
+ break;
+ default:
+ break;
+ }
+ }
+ } else { /* Allow -b without argument for compat. Remove
+ * this eventually so "-b {blocksize}" works */
+ fprintf(stderr, "%s: -b needs a blocksize "
+ "option, assuming 1024-byte blocks.\n",
+ argv[0]);
+ blocksize = 1024;
+ }
+ break;
+ case 'e':
+ force_extent++;
+ if (!verbose)
+ verbose++;
+ break;
+ case 'k':
+ blocksize = 1024;
+ break;
+ case 's':
+ sync_file++;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'x':
+ xattr_map++;
+ break;
+ case 'X':
+ ext_fmt = hex_fmt;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ if (optind == argc)
+ usage(argv[0]);
+ for (cpp=argv+optind; *cpp; cpp++)
+ frag_report(*cpp);
+ return 0;
+}
+#endif
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/findfs.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/findfs.8.in
new file mode 100644
index 0000000..d44cbc7
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/findfs.8.in
@@ -0,0 +1,33 @@
+.\" -*- nroff -*-
+.\" Copyright 1993, 1994, 1995 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH FINDFS 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+findfs \- Find a filesystem by label or UUID
+.SH SYNOPSIS
+.B findfs
+.BI LABEL= label
+.sp
+.B findfs
+.BI UUID= uuid
+.SH DESCRIPTION
+.B findfs
+will search the disks in the system looking for a filesystem which has
+a label matching
+.I label
+or a UUID equal to
+.IR uuid .
+If the filesystem is found, the device name for the filesystem will
+be printed on stdout.
+.PP
+.SH AUTHOR
+.B findfs
+was written by Theodore Ts'o (tytso@mit.edu).
+.SH AVAILABILITY
+.B findfs
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR fsck (8)
+
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/findsuper.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/findsuper.c
new file mode 100644
index 0000000..eb9130b
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/findsuper.c
@@ -0,0 +1,265 @@
+/*
+ * findsuper --- quick hacked up program to find ext2 superblocks.
+ *
+ * This is a hack, and really shouldn't be installed anywhere. If you
+ * need a program which does this sort of functionality, please try
+ * using gpart program.
+ *
+ * Portions Copyright 1998-2000, Theodore Ts'o.
+ *
+ * Well, here's my linux version of findsuper.
+ * I'm sure you coulda done it faster. :)
+ * IMHO there isn't as much interesting data to print in the
+ * linux superblock as there is in the SunOS superblock--disk geometry is
+ * not there...and linux seems to update the dates in all the superblocks.
+ * SunOS doesn't ever touch the backup superblocks after the fs is created,
+ * as far as I can tell, so the date is more interesting IMHO and certainly
+ * marks which superblocks are backup ones.
+ *
+ * I wanted to add msdos support, but I couldn't make heads or tails
+ * of the kernel include files to find anything I could look for in msdos.
+ *
+ * Reading every block of a Sun partition is fairly quick. Doing the
+ * same under linux (slower hardware I suppose) just isn't the same.
+ * It might be more useful to default to reading the first (second?) block
+ * on each cyl; however, if the disk geometry is wrong, this is useless.
+ * But ya could still get the cyl size to print the numbers as cyls instead
+ * of blocks...
+ *
+ * run this as (for example)
+ * findsuper /dev/hda
+ * findsuper /dev/hda 437760 1024 (my disk has cyls of 855*512)
+ *
+ * I suppose the next step is to figgure out a way to determine if
+ * the block found is the first superblock somehow, and if so, build
+ * a partition table from the superblocks found... but this is still
+ * useful as is.
+ *
+ * Steve
+ * ssd@nevets.oau.org
+ * ssd@mae.engr.ucf.edu
+ *
+ * Additional notes by Andreas Dilger <adilger@turbolinux.com>:
+ * - fixed to support > 2G devices by using lseek64
+ * - add reliability checking for the superblock to avoid random garbage
+ * - add adaptive progress meter
+ *
+ * It _should_ also handle signals and tell you the ending block, so
+ * that you can resume at a later time, but it doesn't yet...
+ *
+ * Note that gpart does not appear to find all superblocks that aren't aligned
+ * with the start of a possible partition, so it is not useful in systems
+ * with LVM or similar setups which don't use fat partition alignment.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/*
+ * Documentation addendum added by Andreas dwguest@win.tue.nl/aeb@cwi.nl
+ *
+ * The program findsuper is a utility that scans a disk and finds
+ * copies of ext2 superblocks (by checking for the ext2 signature).
+ *
+ * For each superblock found, it prints the offset in bytes, the
+ * offset in 1024-byte blocks, the size of the ext2 partition in fs
+ * blocks, the filesystem blocksize (in bytes), the block group number
+ * (always 0 for older ext2 systems), and a timestamp (s_mtime).
+ *
+ * This program can be used to retrieve partitions that have been
+ * lost. The superblock for block group 0 is found 1 block (2
+ * sectors) after the partition start.
+ *
+ * For new systems that have a block group number in the superblock it
+ * is immediately clear which superblock is the first of a partition.
+ * For old systems where no group numbers are given, the first
+ * superblock can be recognised by the timestamp: all superblock
+ * copies have the creation time in s_mtime, except the first, which
+ * has the last time e2fsck or tune2fs wrote to the filesystem.
+ *
+ */
+
+#define _FILE_OFFSET_BITS 64
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+#include "nls-enable.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define WHY(fmt, arg...) { printf("\r%Ld: " fmt, sk, ##arg) ; continue; }
+#else
+#define WHY(fmt, arg...) { continue; }
+#endif
+
+static void usage(void)
+{
+ fprintf(stderr,
+ _("Usage: findsuper device [skipbytes [startkb]]\n"));
+ exit(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int skiprate=512; /* one sector */
+ loff_t sk=0, skl=0;
+ int fd;
+ char *s;
+ time_t tm, last = time(0);
+ loff_t interval = 1024 * 1024;
+ int c, print_jnl_copies = 0;
+ const char * device_name;
+ struct ext2_super_block ext2;
+ /* interesting fields: EXT2_SUPER_MAGIC
+ * s_blocks_count s_log_block_size s_mtime s_magic s_lastcheck */
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+
+ while ((c = getopt (argc, argv, "j")) != EOF) {
+ switch (c) {
+ case 'j':
+ print_jnl_copies++;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (optind == argc)
+ usage();
+
+ device_name = argv[optind++];
+
+ if (optind < argc) {
+ skiprate = strtol(argv[optind], &s, 0);
+ if (s == argv[optind]) {
+ fprintf(stderr,_("skipbytes should be a number, not %s\n"), s);
+ exit(1);
+ }
+ optind++;
+ }
+ if (skiprate & 0x1ff) {
+ fprintf(stderr,
+ _("skipbytes must be a multiple of the sector size\n"));
+ exit(2);
+ }
+ if (optind < argc) {
+ sk = skl = strtoll(argv[optind], &s, 0) << 10;
+ if (s == argv[optind]) {
+ fprintf(stderr,
+ _("startkb should be a number, not %s\n"), s);
+ exit(1);
+ }
+ optind++;
+ }
+ if (sk < 0) {
+ fprintf(stderr, _("startkb should be positive, not %llu\n"),sk);
+ exit(1);
+ }
+
+ fd = open(device_name, O_RDONLY);
+ if (fd < 0) {
+ perror(device_name);
+ exit(1);
+ }
+
+ /* Now, go looking for the superblock! */
+ printf(_("starting at %llu, with %u byte increments\n"), sk, skiprate);
+ if (print_jnl_copies)
+ printf(_("[*] probably superblock written in the ext3 "
+ "journal superblock,\n\tso start/end/grp wrong\n"));
+ printf(_("byte_offset byte_start byte_end fs_blocks blksz grp last_mount_time sb_uuid label\n"));
+ for (; lseek64(fd, sk, SEEK_SET) != -1 &&
+ read(fd, &ext2, 512) == 512; sk += skiprate) {
+ static unsigned char last_uuid[16] = "blah";
+ unsigned long long bsize, grpsize;
+ int jnl_copy, sb_offset;
+
+ if (sk && !(sk & (interval - 1))) {
+ time_t now, diff;
+
+ now = time(0);
+ diff = now - last;
+
+ if (diff > 0) {
+ s = ctime(&now);
+ s[24] = 0;
+ printf("\r%11Lu: %8LukB/s @ %s", sk,
+ (((sk - skl)) / diff) >> 10, s);
+ fflush(stdout);
+ }
+ if (diff < 5)
+ interval <<= 1;
+ else if (diff > 20)
+ interval >>= 1;
+ last = now;
+ skl = sk;
+ }
+ if (ext2.s_magic != EXT2_SUPER_MAGIC)
+ continue;
+ if (ext2.s_log_block_size > 6)
+ WHY("log block size > 6 (%u)\n", ext2.s_log_block_size);
+ if (ext2fs_r_blocks_count(&ext2) > ext2fs_blocks_count(&ext2))
+ WHY("r_blocks_count > blocks_count (%u > %u)\n",
+ ext2fs_r_blocks_count(&ext2),
+ ext2fs_blocks_count(&ext2));
+ if (ext2fs_free_blocks_count(&ext2) > ext2fs_blocks_count(&ext2))
+ WHY("free_blocks_count > blocks_count\n (%u > %u)\n",
+ ext2fs_free_blocks_count(&ext2),
+ ext2fs_blocks_count(&ext2));
+ if (ext2.s_free_inodes_count > ext2.s_inodes_count)
+ WHY("free_inodes_count > inodes_count (%u > %u)\n",
+ ext2.s_free_inodes_count, ext2.s_inodes_count);
+
+ tm = ext2.s_mtime;
+ s = ctime(&tm);
+ s[24] = 0;
+ bsize = 1 << (ext2.s_log_block_size + 10);
+ grpsize = bsize * ext2.s_blocks_per_group;
+ if (memcmp(ext2.s_uuid, last_uuid, sizeof(last_uuid)) == 0 &&
+ ext2.s_rev_level > 0 && ext2.s_block_group_nr == 0) {
+ jnl_copy = 1;
+ } else {
+ jnl_copy = 0;
+ memcpy(last_uuid, ext2.s_uuid, sizeof(last_uuid));
+ }
+ if (ext2.s_block_group_nr == 0 || bsize == 1024)
+ sb_offset = 1024;
+ else
+ sb_offset = 0;
+ if (jnl_copy && !print_jnl_copies)
+ continue;
+ printf("\r%11Lu %11Lu%s %11Lu%s %9u %5Lu %4u%s %s %02x%02x%02x%02x %s\n",
+ sk, sk - ext2.s_block_group_nr * grpsize - sb_offset,
+ jnl_copy ? "*":" ",
+ sk + ext2fs_blocks_count(&ext2) * bsize -
+ ext2.s_block_group_nr * grpsize - sb_offset,
+ jnl_copy ? "*" : " ", ext2fs_blocks_count(&ext2), bsize,
+ ext2.s_block_group_nr, jnl_copy ? "*" : " ", s,
+ ext2.s_uuid[0], ext2.s_uuid[1],
+ ext2.s_uuid[2], ext2.s_uuid[3], ext2.s_volume_name);
+ }
+ printf(_("\n%11Lu: finished with errno %d\n"), sk, errno);
+ close(fd);
+
+ return errno;
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/fsck.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/fsck.8.in
new file mode 100644
index 0000000..50fd8ce
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/fsck.8.in
@@ -0,0 +1,414 @@
+.\" -*- nroff -*-
+.\" Copyright 1993, 1994, 1995 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH FSCK 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+fsck \- check and repair a Linux file system
+.SH SYNOPSIS
+.B fsck
+[
+.B \-sAVRTMNP
+]
+[
+.B \-C
+[
+.I fd
+]
+]
+[
+.B \-t
+.I fstype
+]
+.I [filesys ... ]
+[\-\-] [
+.B fs-specific-options
+]
+.SH DESCRIPTION
+.B fsck
+is used to check and optionally repair one or more Linux file systems.
+.I filesys
+can be a device name (e.g.
+.IR /dev/hdc1 ", " /dev/sdb2 ),
+a mount point (e.g.
+.IR / ", " /usr ", " /home ),
+or an ext2 label or UUID specifier (e.g.
+UUID=8868abf6-88c5-4a83-98b8-bfc24057f7bd or LABEL=root).
+Normally, the
+.B fsck
+program will try to handle filesystems on different physical disk drives
+in parallel to reduce the total amount of time needed to check all of the
+filesystems.
+.PP
+If no filesystems are specified on the command line, and the
+.B \-A
+option is not specified,
+.B fsck
+will default to checking filesystems in
+.B /etc/fstab
+serially. This is equivalent to the
+.B \-As
+options.
+.PP
+The exit code returned by
+.B fsck
+is the sum of the following conditions:
+.br
+\ 0\ \-\ No errors
+.br
+\ 1\ \-\ File system errors corrected
+.br
+\ 2\ \-\ System should be rebooted
+.br
+\ 4\ \-\ File system errors left uncorrected
+.br
+\ 8\ \-\ Operational error
+.br
+\ 16\ \-\ Usage or syntax error
+.br
+\ 32\ \-\ Fsck canceled by user request
+.br
+\ 128\ \-\ Shared library error
+.br
+The exit code returned when multiple file systems are checked
+is the bit-wise OR of the exit codes for each
+file system that is checked.
+.PP
+In actuality,
+.B fsck
+is simply a front-end for the various file system checkers
+(\fBfsck\fR.\fIfstype\fR) available under Linux. The file
+system-specific checker is searched for in
+.I /sbin
+first, then in
+.I /etc/fs
+and
+.IR /etc ,
+and finally in the directories listed in the PATH environment
+variable. Please see the file system-specific checker manual pages for
+further details.
+.SH OPTIONS
+.TP
+.B \-s
+Serialize
+.B fsck
+operations. This is a good idea if you are checking multiple
+filesystems and the checkers are in an interactive mode. (Note:
+.BR e2fsck (8)
+runs in an interactive mode by default. To make
+.BR e2fsck (8)
+run in a non-interactive mode, you must either specify the
+.B \-p
+or
+.B \-a
+option, if you wish for errors to be corrected automatically, or the
+.B \-n
+option if you do not.)
+.TP
+.BI \-t " fslist"
+Specifies the type(s) of file system to be checked. When the
+.B \-A
+flag is specified, only filesystems that match
+.I fslist
+are checked. The
+.I fslist
+parameter is a comma-separated list of filesystems and options
+specifiers. All of the filesystems in this comma-separated list may be
+prefixed by a negation operator
+.RB ' no '
+or
+.RB ' ! ',
+which requests that only those filesystems not listed in
+.I fslist
+will be checked. If all of the filesystems in
+.I fslist
+are not prefixed by a negation operator, then only those filesystems
+listed
+in
+.I fslist
+will be checked.
+.sp
+Options specifiers may be included in the comma-separated
+.IR fslist .
+They must have the format
+.BI opts= fs-option\fR.
+If an options specifier is present, then only filesystems which contain
+.I fs-option
+in their mount options field of
+.B /etc/fstab
+will be checked. If the options specifier is prefixed by a negation
+operator, then only
+those filesystems that do not have
+.I fs-option
+in their mount options field of
+.B /etc/fstab
+will be checked.
+.sp
+For example, if
+.B opts=ro
+appears in
+.IR fslist ,
+then only filesystems listed in
+.B /etc/fstab
+with the
+.B ro
+option will be checked.
+.sp
+For compatibility with Mandrake distributions whose boot scripts
+depend upon an unauthorized UI change to the
+.B fsck
+program, if a filesystem type of
+.B loop
+is found in
+.IR fslist ,
+it is treated as if
+.B opts=loop
+were specified as an argument to the
+.B \-t
+option.
+.sp
+Normally, the filesystem type is deduced by searching for
+.I filesys
+in the
+.I /etc/fstab
+file and using the corresponding entry.
+If the type can not be deduced, and there is only a single filesystem
+given as an argument to the
+.B \-t
+option,
+.B fsck
+will use the specified filesystem type. If this type is not
+available, then the default file system type (currently ext2) is used.
+.TP
+.B \-A
+Walk through the
+.I /etc/fstab
+file and try to check all file systems in one run. This option is
+typically used from the
+.I /etc/rc
+system initialization file, instead of multiple commands for checking
+a single file system.
+.sp
+The root filesystem will be checked first unless the
+.B \-P
+option is specified (see below). After that,
+filesystems will be checked in the order specified by the
+.I fs_passno
+(the sixth) field in the
+.I /etc/fstab
+file.
+Filesystems with a
+.I fs_passno
+value of 0 are skipped and are not checked at all. Filesystems with a
+.I fs_passno
+value of greater than zero will be checked in order,
+with filesystems with the lowest
+.I fs_passno
+number being checked first.
+If there are multiple filesystems with the same pass number,
+fsck will attempt to check them in parallel, although it will avoid running
+multiple filesystem checks on the same physical disk.
+.sp
+Hence, a very common configuration in
+.I /etc/fstab
+files is to set the root filesystem to have a
+.I fs_passno
+value of 1
+and to set all other filesystems to have a
+.I fs_passno
+value of 2. This will allow
+.B fsck
+to automatically run filesystem checkers in parallel if it is advantageous
+to do so. System administrators might choose
+not to use this configuration if they need to avoid multiple filesystem
+checks running in parallel for some reason --- for example, if the
+machine in question is short on memory so that
+excessive paging is a concern.
+.TP
+.B \-C\fR [ \fI "fd" \fR ]
+Display completion/progress bars for those filesystem checkers (currently
+only for ext2 and ext3) which support them. Fsck will manage the
+filesystem checkers so that only one of them will display
+a progress bar at a time. GUI front-ends may specify a file descriptor
+.IR fd ,
+in which case the progress bar information will be sent to that file descriptor.
+.TP
+.B \-M
+Do not check mounted filesystems and return an exit code of 0
+for mounted filesystems.
+.TP
+.B \-N
+Don't execute, just show what would be done.
+.TP
+.B \-P
+When the
+.B \-A
+flag is set, check the root filesystem in parallel with the other filesystems.
+This is not the safest thing in the world to do,
+since if the root filesystem is in doubt things like the
+.BR e2fsck (8)
+executable might be corrupted! This option is mainly provided
+for those sysadmins who don't want to repartition the root
+filesystem to be small and compact (which is really the right solution).
+.TP
+.B \-R
+When checking all file systems with the
+.B \-A
+flag, skip the root file system (in case it's already mounted read-write).
+.TP
+.B \-T
+Don't show the title on startup.
+.TP
+.B \-V
+Produce verbose output, including all file system-specific commands
+that are executed.
+.TP
+.B fs-specific-options
+Options which are not understood by
+.B fsck
+are passed to the filesystem-specific checker. These arguments
+.B must
+not take arguments, as there is no
+way for
+.B fsck
+to be able to properly guess which arguments take options and which
+don't.
+.IP
+Options and arguments which follow the
+.B \-\-
+are treated as file system-specific options to be passed to the
+file system-specific checker.
+.IP
+Please note that fsck is not
+designed to pass arbitrarily complicated options to filesystem-specific
+checkers. If you're doing something complicated, please just
+execute the filesystem-specific checker directly. If you pass
+.B fsck
+some horribly complicated option and arguments, and it doesn't do
+what you expect,
+.B don't bother reporting it as a bug.
+You're almost certainly doing something that you shouldn't be doing
+with
+.BR fsck.
+.PP
+Options to different filesystem-specific fsck's are not standardized.
+If in doubt, please consult the man pages of the filesystem-specific
+checker. Although not guaranteed, the following options are supported
+by most file system checkers:
+.TP
+.B \-a
+Automatically repair the file system without any questions (use
+this option with caution). Note that
+.BR e2fsck (8)
+supports
+.B \-a
+for backwards compatibility only. This option is mapped to
+.BR e2fsck 's
+.B \-p
+option which is safe to use, unlike the
+.B \-a
+option that some file system checkers support.
+.TP
+.B \-n
+For some filesystem-specific checkers, the
+.B \-n
+option will cause the fs-specific fsck to avoid attempting to repair any
+problems, but simply report such problems to stdout. This is however
+not true for all filesystem-specific checkers. In particular,
+.BR fsck.reiserfs (8)
+will not report any corruption if given this option.
+.BR fsck.minix (8)
+does not support the
+.B \-n
+option at all.
+.TP
+.B \-r
+Interactively repair the filesystem (ask for confirmations). Note: It
+is generally a bad idea to use this option if multiple fsck's are being
+run in parallel. Also note that this is
+.BR e2fsck 's
+default behavior; it supports this option for backwards compatibility
+reasons only.
+.TP
+.B \-y
+For some filesystem-specific checkers, the
+.B \-y
+option will cause the fs-specific fsck to always attempt to fix any
+detected filesystem corruption automatically. Sometimes an expert may
+be able to do better driving the fsck manually. Note that
+.B not
+all filesystem-specific checkers implement this option. In particular
+.BR fsck.minix (8)
+and
+.BR fsck.cramfs (8)
+does not support the
+.B -y
+option as of this writing.
+.SH AUTHOR
+Theodore Ts'o (tytso@mit.edu)
+.SH FILES
+.IR /etc/fstab .
+.SH ENVIRONMENT VARIABLES
+The
+.B fsck
+program's behavior is affected by the following environment variables:
+.TP
+.B FSCK_FORCE_ALL_PARALLEL
+If this environment variable is set,
+.B fsck
+will attempt to run all of the specified filesystems in parallel,
+regardless of whether the filesystems appear to be on the same
+device. (This is useful for RAID systems or high-end storage systems
+such as those sold by companies such as IBM or EMC.)
+.TP
+.B FSCK_MAX_INST
+This environment variable will limit the maximum number of file system
+checkers that can be running at one time. This allows configurations
+which have a large number of disks to avoid
+.B fsck
+starting too many file system checkers at once, which might overload
+CPU and memory resources available on the system. If this value is
+zero, then an unlimited number of processes can be spawned. This is
+currently the default, but future versions of
+.B fsck
+may attempt to automatically determine how many file system checks can
+be run based on gathering accounting data from the operating system.
+.TP
+.B PATH
+The
+.B PATH
+environment variable is used to find file system checkers. A set of
+system directories are searched first:
+.BR /sbin ,
+.BR /sbin/fs.d ,
+.BR /sbin/fs ,
+.BR /etc/fs ,
+and
+.BR /etc .
+Then the set of directories found in the
+.B PATH
+environment are searched.
+.TP
+.B FSTAB_FILE
+This environment variable allows the system administrator
+to override the standard location of the
+.B /etc/fstab
+file. It is also useful for developers who are testing
+.BR fsck .
+.SH SEE ALSO
+.BR fstab (5),
+.BR mkfs (8),
+.BR fsck.ext2 (8)
+or
+.BR fsck.ext3 (8)
+or
+.BR e2fsck (8),
+.BR cramfsck (8),
+.BR fsck.minix (8),
+.BR fsck.msdos (8),
+.BR fsck.jfs (8),
+.BR fsck.nfs (8),
+.BR fsck.vfat (8),
+.BR fsck.xfs (8),
+.BR fsck.xiafs (8),
+.BR reiserfsck (8).
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/fsck.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/fsck.c
new file mode 100644
index 0000000..826aaeb
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/fsck.c
@@ -0,0 +1,1343 @@
+/*
+ * pfsck --- A generic, parallelizing front-end for the fsck program.
+ * It will automatically try to run fsck programs in parallel if the
+ * devices are on separate spindles. It is based on the same ideas as
+ * the generic front end for fsck by David Engel and Fred van Kempen,
+ * but it has been completely rewritten from scratch to support
+ * parallel execution.
+ *
+ * Written by Theodore Ts'o, <tytso@mit.edu>
+ *
+ * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994:
+ * o Changed -t fstype to behave like with mount when -A (all file
+ * systems) or -M (like mount) is specified.
+ * o fsck looks if it can find the fsck.type program to decide
+ * if it should ignore the fs type. This way more fsck programs
+ * can be added without changing this front-end.
+ * o -R flag skip root file system.
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */
+
+#include "config.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_PATHS_H
+#include <paths.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#include "../version.h"
+#include "nls-enable.h"
+#include "fsck.h"
+#include "blkid/blkid.h"
+
+#ifndef _PATH_MNTTAB
+#define _PATH_MNTTAB "/etc/fstab"
+#endif
+
+static const char *ignored_types[] = {
+ "ignore",
+ "iso9660",
+ "nfs",
+ "proc",
+ "sw",
+ "swap",
+ "tmpfs",
+ "devpts",
+ NULL
+};
+
+static const char *really_wanted[] = {
+ "minix",
+ "ext2",
+ "ext3",
+ "ext4",
+ "ext4dev",
+ "jfs",
+ "reiserfs",
+ "xiafs",
+ "xfs",
+ NULL
+};
+
+#define BASE_MD "/dev/md"
+
+/*
+ * Global variables for options
+ */
+static char *devices[MAX_DEVICES];
+static char *args[MAX_ARGS];
+static int num_devices, num_args;
+
+static int verbose = 0;
+static int doall = 0;
+static int noexecute = 0;
+static int serialize = 0;
+static int skip_root = 0;
+static int ignore_mounted = 0;
+static int notitle = 0;
+static int parallel_root = 0;
+static int progress = 0;
+static int progress_fd = 0;
+static int force_all_parallel = 0;
+static int num_running = 0;
+static int max_running = 0;
+static volatile int cancel_requested = 0;
+static int kill_sent = 0;
+static char *progname;
+static char *fstype = NULL;
+static struct fs_info *filesys_info = NULL, *filesys_last = NULL;
+static struct fsck_instance *instance_list;
+static const char *fsck_prefix_path = "/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc";
+static char *fsck_path = 0;
+static blkid_cache cache = NULL;
+
+static char *string_copy(const char *s)
+{
+ char *ret;
+
+ if (!s)
+ return 0;
+ ret = malloc(strlen(s)+1);
+ if (ret)
+ strcpy(ret, s);
+ return ret;
+}
+
+static int string_to_int(const char *s)
+{
+ long l;
+ char *p;
+
+ l = strtol(s, &p, 0);
+ if (*p || l == LONG_MIN || l == LONG_MAX || l < 0 || l > INT_MAX)
+ return -1;
+ else
+ return (int) l;
+}
+
+static int ignore(struct fs_info *);
+
+static char *skip_over_blank(char *cp)
+{
+ while (*cp && isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static char *skip_over_word(char *cp)
+{
+ while (*cp && !isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static void strip_line(char *line)
+{
+ char *p;
+
+ while (*line) {
+ p = line + strlen(line) - 1;
+ if ((*p == '\n') || (*p == '\r'))
+ *p = 0;
+ else
+ break;
+ }
+}
+
+static char *parse_word(char **buf)
+{
+ char *word, *next;
+
+ word = *buf;
+ if (*word == 0)
+ return 0;
+
+ word = skip_over_blank(word);
+ next = skip_over_word(word);
+ if (*next)
+ *next++ = 0;
+ *buf = next;
+ return word;
+}
+
+static void parse_escape(char *word)
+{
+ char *p, *q;
+ int ac, i;
+
+ if (!word)
+ return;
+
+ for (p = word, q = word; *p; p++, q++) {
+ *q = *p;
+ if (*p != '\\')
+ continue;
+ if (*++p == 0)
+ break;
+ if (*p == 't') {
+ *q = '\t';
+ continue;
+ }
+ if (*p == 'n') {
+ *q = '\n';
+ continue;
+ }
+ if (!isdigit(*p)) {
+ *q = *p;
+ continue;
+ }
+ ac = 0;
+ for (i = 0; i < 3; i++, p++) {
+ if (!isdigit(*p))
+ break;
+ ac = (ac * 8) + (*p - '0');
+ }
+ *q = ac;
+ p--;
+ }
+ *q = 0;
+}
+
+static void free_instance(struct fsck_instance *i)
+{
+ free(i->prog);
+ free(i->device);
+ free(i->base_device);
+ free(i);
+ return;
+}
+
+static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
+ const char *type, const char *opts,
+ int freq, int passno)
+{
+ struct fs_info *fs;
+
+ if (!(fs = malloc(sizeof(struct fs_info))))
+ return NULL;
+
+ fs->device = string_copy(device);
+ fs->mountpt = string_copy(mntpnt);
+ fs->type = string_copy(type);
+ fs->opts = string_copy(opts ? opts : "");
+ fs->freq = freq;
+ fs->passno = passno;
+ fs->flags = 0;
+ fs->next = NULL;
+
+ if (!filesys_info)
+ filesys_info = fs;
+ else
+ filesys_last->next = fs;
+ filesys_last = fs;
+
+ return fs;
+}
+
+
+
+static int parse_fstab_line(char *line, struct fs_info **ret_fs)
+{
+ char *dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
+ struct fs_info *fs;
+
+ *ret_fs = 0;
+ strip_line(line);
+ cp = line;
+
+ device = parse_word(&cp);
+ if (!device || *device == '#')
+ return 0; /* Ignore blank lines and comments */
+ mntpnt = parse_word(&cp);
+ type = parse_word(&cp);
+ opts = parse_word(&cp);
+ freq = parse_word(&cp);
+ passno = parse_word(&cp);
+
+ if (!mntpnt || !type)
+ return -1;
+
+ parse_escape(device);
+ parse_escape(mntpnt);
+ parse_escape(type);
+ parse_escape(opts);
+ parse_escape(freq);
+ parse_escape(passno);
+
+ dev = blkid_get_devname(cache, device, NULL);
+ if (dev)
+ device = dev;
+
+ if (strchr(type, ','))
+ type = 0;
+
+ fs = create_fs_device(device, mntpnt, type ? type : "auto", opts,
+ freq ? atoi(freq) : -1,
+ passno ? atoi(passno) : -1);
+ free(dev);
+
+ if (!fs)
+ return -1;
+ *ret_fs = fs;
+ return 0;
+}
+
+static void interpret_type(struct fs_info *fs)
+{
+ char *t;
+
+ if (strcmp(fs->type, "auto") != 0)
+ return;
+ t = blkid_get_tag_value(cache, "TYPE", fs->device);
+ if (t) {
+ free(fs->type);
+ fs->type = t;
+ }
+}
+
+/*
+ * Load the filesystem database from /etc/fstab
+ */
+static void load_fs_info(const char *filename)
+{
+ FILE *f;
+ char buf[1024];
+ int lineno = 0;
+ int old_fstab = 1;
+ struct fs_info *fs;
+
+ if ((f = fopen(filename, "r")) == NULL) {
+ fprintf(stderr, _("WARNING: couldn't open %s: %s\n"),
+ filename, strerror(errno));
+ return;
+ }
+ while (!feof(f)) {
+ lineno++;
+ if (!fgets(buf, sizeof(buf), f))
+ break;
+ buf[sizeof(buf)-1] = 0;
+ if (parse_fstab_line(buf, &fs) < 0) {
+ fprintf(stderr, _("WARNING: bad format "
+ "on line %d of %s\n"), lineno, filename);
+ continue;
+ }
+ if (!fs)
+ continue;
+ if (fs->passno < 0)
+ fs->passno = 0;
+ else
+ old_fstab = 0;
+ }
+
+ fclose(f);
+
+ if (old_fstab && filesys_info) {
+ fputs("\007\007\007", stderr);
+ fputs(_(
+ "WARNING: Your /etc/fstab does not contain the fsck passno\n"
+ " field. I will kludge around things for you, but you\n"
+ " should fix your /etc/fstab file as soon as you can.\n\n"), stderr);
+
+ for (fs = filesys_info; fs; fs = fs->next) {
+ fs->passno = 1;
+ }
+ }
+}
+
+/* Lookup filesys in /etc/fstab and return the corresponding entry. */
+static struct fs_info *lookup(char *filesys)
+{
+ struct fs_info *fs;
+
+ /* No filesys name given. */
+ if (filesys == NULL)
+ return NULL;
+
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (!strcmp(filesys, fs->device) ||
+ (fs->mountpt && !strcmp(filesys, fs->mountpt)))
+ break;
+ }
+
+ return fs;
+}
+
+/* Find fsck program for a given fs type. */
+static char *find_fsck(char *type)
+{
+ char *s;
+ const char *tpl;
+ static char prog[256];
+ char *p = string_copy(fsck_path);
+ struct stat st;
+
+ /* Are we looking for a program or just a type? */
+ tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s");
+
+ for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) {
+ sprintf(prog, tpl, s, type);
+ if (stat(prog, &st) == 0) break;
+ }
+ free(p);
+ return(s ? prog : NULL);
+}
+
+static int progress_active(NOARGS)
+{
+ struct fsck_instance *inst;
+
+ for (inst = instance_list; inst; inst = inst->next) {
+ if (inst->flags & FLAG_DONE)
+ continue;
+ if (inst->flags & FLAG_PROGRESS)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Execute a particular fsck program, and link it into the list of
+ * child processes we are waiting for.
+ */
+static int execute(const char *type, const char *device, const char *mntpt,
+ int interactive)
+{
+ char *s, *argv[80], prog[80];
+ int argc, i;
+ struct fsck_instance *inst, *p;
+ pid_t pid;
+
+ inst = malloc(sizeof(struct fsck_instance));
+ if (!inst)
+ return ENOMEM;
+ memset(inst, 0, sizeof(struct fsck_instance));
+
+ sprintf(prog, "fsck.%s", type);
+ argv[0] = string_copy(prog);
+ argc = 1;
+
+ for (i=0; i <num_args; i++)
+ argv[argc++] = string_copy(args[i]);
+
+ if (progress) {
+ if ((strcmp(type, "ext2") == 0) ||
+ (strcmp(type, "ext3") == 0) ||
+ (strcmp(type, "ext4") == 0) ||
+ (strcmp(type, "ext4dev") == 0)) {
+ char tmp[80];
+
+ tmp[0] = 0;
+ if (!progress_active()) {
+ snprintf(tmp, 80, "-C%d", progress_fd);
+ inst->flags |= FLAG_PROGRESS;
+ } else if (progress_fd)
+ snprintf(tmp, 80, "-C%d", progress_fd * -1);
+ if (tmp[0])
+ argv[argc++] = string_copy(tmp);
+ }
+ }
+
+ argv[argc++] = string_copy(device);
+ argv[argc] = 0;
+
+ s = find_fsck(prog);
+ if (s == NULL) {
+ fprintf(stderr, _("fsck: %s: not found\n"), prog);
+ free(inst);
+ return ENOENT;
+ }
+
+ if (verbose || noexecute) {
+ printf("[%s (%d) -- %s] ", s, num_running,
+ mntpt ? mntpt : device);
+ for (i=0; i < argc; i++)
+ printf("%s ", argv[i]);
+ printf("\n");
+ }
+
+ /* Fork and execute the correct program. */
+ if (noexecute)
+ pid = -1;
+ else if ((pid = fork()) < 0) {
+ perror("fork");
+ free(inst);
+ return errno;
+ } else if (pid == 0) {
+ if (!interactive)
+ close(0);
+ (void) execv(s, argv);
+ perror(argv[0]);
+ free(inst);
+ exit(EXIT_ERROR);
+ }
+
+ for (i=0; i < argc; i++)
+ free(argv[i]);
+
+ inst->pid = pid;
+ inst->prog = string_copy(prog);
+ inst->type = string_copy(type);
+ inst->device = string_copy(device);
+ inst->base_device = base_device(device);
+ inst->start_time = time(0);
+ inst->next = NULL;
+
+ /*
+ * Find the end of the list, so we add the instance on at the end.
+ */
+ for (p = instance_list; p && p->next; p = p->next);
+
+ if (p)
+ p->next = inst;
+ else
+ instance_list = inst;
+
+ return 0;
+}
+
+/*
+ * Send a signal to all outstanding fsck child processes
+ */
+static int kill_all(int signum)
+{
+ struct fsck_instance *inst;
+ int n = 0;
+
+ for (inst = instance_list; inst; inst = inst->next) {
+ if (inst->flags & FLAG_DONE)
+ continue;
+ kill(inst->pid, signum);
+ n++;
+ }
+ return n;
+}
+
+/*
+ * Wait for one child process to exit; when it does, unlink it from
+ * the list of executing child processes, and return it.
+ */
+static struct fsck_instance *wait_one(int flags)
+{
+ int status;
+ int sig;
+ struct fsck_instance *inst, *inst2, *prev;
+ pid_t pid;
+
+ if (!instance_list)
+ return NULL;
+
+ if (noexecute) {
+ inst = instance_list;
+ prev = 0;
+#ifdef RANDOM_DEBUG
+ while (inst->next && (random() & 1)) {
+ prev = inst;
+ inst = inst->next;
+ }
+#endif
+ inst->exit_status = 0;
+ goto ret_inst;
+ }
+
+ /*
+ * gcc -Wall fails saving throw against stupidity
+ * (inst and prev are thought to be uninitialized variables)
+ */
+ inst = prev = NULL;
+
+ do {
+ pid = waitpid(-1, &status, flags);
+ if (cancel_requested && !kill_sent) {
+ kill_all(SIGTERM);
+ kill_sent++;
+ }
+ if ((pid == 0) && (flags & WNOHANG))
+ return NULL;
+ if (pid < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ if (errno == ECHILD) {
+ fprintf(stderr,
+ _("%s: wait: No more child process?!?\n"),
+ progname);
+ return NULL;
+ }
+ perror("wait");
+ continue;
+ }
+ for (prev = 0, inst = instance_list;
+ inst;
+ prev = inst, inst = inst->next) {
+ if (inst->pid == pid)
+ break;
+ }
+ } while (!inst);
+
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status)) {
+ sig = WTERMSIG(status);
+ if (sig == SIGINT) {
+ status = EXIT_UNCORRECTED;
+ } else {
+ printf(_("Warning... %s for device %s exited "
+ "with signal %d.\n"),
+ inst->prog, inst->device, sig);
+ status = EXIT_ERROR;
+ }
+ } else {
+ printf(_("%s %s: status is %x, should never happen.\n"),
+ inst->prog, inst->device, status);
+ status = EXIT_ERROR;
+ }
+ inst->exit_status = status;
+ inst->flags |= FLAG_DONE;
+ if (progress && (inst->flags & FLAG_PROGRESS) &&
+ !progress_active()) {
+ for (inst2 = instance_list; inst2; inst2 = inst2->next) {
+ if (inst2->flags & FLAG_DONE)
+ continue;
+ if (strcmp(inst2->type, "ext2") &&
+ strcmp(inst2->type, "ext3") &&
+ strcmp(inst2->type, "ext4") &&
+ strcmp(inst2->type, "ext4dev"))
+ continue;
+ /*
+ * If we've just started the fsck, wait a tiny
+ * bit before sending the kill, to give it
+ * time to set up the signal handler
+ */
+ if (inst2->start_time < time(0)+2) {
+ if (fork() == 0) {
+ sleep(1);
+ kill(inst2->pid, SIGUSR1);
+ exit(0);
+ }
+ } else
+ kill(inst2->pid, SIGUSR1);
+ inst2->flags |= FLAG_PROGRESS;
+ break;
+ }
+ }
+ret_inst:
+ if (prev)
+ prev->next = inst->next;
+ else
+ instance_list = inst->next;
+ if (verbose > 1)
+ printf(_("Finished with %s (exit status %d)\n"),
+ inst->device, inst->exit_status);
+ num_running--;
+ return inst;
+}
+
+#define FLAG_WAIT_ALL 0
+#define FLAG_WAIT_ATLEAST_ONE 1
+/*
+ * Wait until all executing child processes have exited; return the
+ * logical OR of all of their exit code values.
+ */
+static int wait_many(int flags)
+{
+ struct fsck_instance *inst;
+ int global_status = 0;
+ int wait_flags = 0;
+
+ while ((inst = wait_one(wait_flags))) {
+ global_status |= inst->exit_status;
+ free_instance(inst);
+#ifdef RANDOM_DEBUG
+ if (noexecute && (flags & WNOHANG) && !(random() % 3))
+ break;
+#endif
+ if (flags & FLAG_WAIT_ATLEAST_ONE)
+ wait_flags = WNOHANG;
+ }
+ return global_status;
+}
+
+/*
+ * Run the fsck program on a particular device
+ *
+ * If the type is specified using -t, and it isn't prefixed with "no"
+ * (as in "noext2") and only one filesystem type is specified, then
+ * use that type regardless of what is specified in /etc/fstab.
+ *
+ * If the type isn't specified by the user, then use either the type
+ * specified in /etc/fstab, or DEFAULT_FSTYPE.
+ */
+static void fsck_device(struct fs_info *fs, int interactive)
+{
+ const char *type;
+ int retval;
+
+ interpret_type(fs);
+
+ if (strcmp(fs->type, "auto") != 0)
+ type = fs->type;
+ else if (fstype && strncmp(fstype, "no", 2) &&
+ strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) &&
+ !strchr(fstype, ','))
+ type = fstype;
+ else
+ type = DEFAULT_FSTYPE;
+
+ num_running++;
+ retval = execute(type, fs->device, fs->mountpt, interactive);
+ if (retval) {
+ fprintf(stderr, _("%s: Error %d while executing fsck.%s "
+ "for %s\n"), progname, retval, type, fs->device);
+ num_running--;
+ }
+}
+
+
+/*
+ * Deal with the fsck -t argument.
+ */
+static struct fs_type_compile {
+ char **list;
+ int *type;
+ int negate;
+} fs_type_compiled;
+
+#define FS_TYPE_NORMAL 0
+#define FS_TYPE_OPT 1
+#define FS_TYPE_NEGOPT 2
+
+static const char *fs_type_syntax_error =
+N_("Either all or none of the filesystem types passed to -t must be prefixed\n"
+ "with 'no' or '!'.\n");
+
+static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp)
+{
+ char *cp, *list, *s;
+ int num = 2;
+ int negate, first_negate = 1;
+
+ if (fs_type) {
+ for (cp=fs_type; *cp; cp++) {
+ if (*cp == ',')
+ num++;
+ }
+ }
+
+ cmp->list = malloc(num * sizeof(char *));
+ cmp->type = malloc(num * sizeof(int));
+ if (!cmp->list || !cmp->type) {
+ fputs(_("Couldn't allocate memory for filesystem types\n"),
+ stderr);
+ exit(EXIT_ERROR);
+ }
+ memset(cmp->list, 0, num * sizeof(char *));
+ memset(cmp->type, 0, num * sizeof(int));
+ cmp->negate = 0;
+
+ if (!fs_type)
+ return;
+
+ list = string_copy(fs_type);
+ num = 0;
+ s = strtok(list, ",");
+ while(s) {
+ negate = 0;
+ if (strncmp(s, "no", 2) == 0) {
+ s += 2;
+ negate = 1;
+ } else if (*s == '!') {
+ s++;
+ negate = 1;
+ }
+ if (strcmp(s, "loop") == 0)
+ /* loop is really short-hand for opts=loop */
+ goto loop_special_case;
+ else if (strncmp(s, "opts=", 5) == 0) {
+ s += 5;
+ loop_special_case:
+ cmp->type[num] = negate ? FS_TYPE_NEGOPT : FS_TYPE_OPT;
+ } else {
+ if (first_negate) {
+ cmp->negate = negate;
+ first_negate = 0;
+ }
+ if ((negate && !cmp->negate) ||
+ (!negate && cmp->negate)) {
+ fputs(_(fs_type_syntax_error), stderr);
+ exit(EXIT_USAGE);
+ }
+ }
+#if 0
+ printf("Adding %s to list (type %d).\n", s, cmp->type[num]);
+#endif
+ cmp->list[num++] = string_copy(s);
+ s = strtok(NULL, ",");
+ }
+ free(list);
+}
+
+/*
+ * This function returns true if a particular option appears in a
+ * comma-delimited options list
+ */
+static int opt_in_list(const char *opt, char *optlist)
+{
+ char *list, *s;
+
+ if (!optlist)
+ return 0;
+ list = string_copy(optlist);
+
+ s = strtok(list, ",");
+ while(s) {
+ if (strcmp(s, opt) == 0) {
+ free(list);
+ return 1;
+ }
+ s = strtok(NULL, ",");
+ }
+ free(list);
+ return 0;
+}
+
+/* See if the filesystem matches the criteria given by the -t option */
+static int fs_match(struct fs_info *fs, struct fs_type_compile *cmp)
+{
+ int n, ret = 0, checked_type = 0;
+ char *cp;
+
+ if (cmp->list == 0 || cmp->list[0] == 0)
+ return 1;
+
+ for (n=0; (cp = cmp->list[n]); n++) {
+ switch (cmp->type[n]) {
+ case FS_TYPE_NORMAL:
+ checked_type++;
+ if (strcmp(cp, fs->type) == 0) {
+ ret = 1;
+ }
+ break;
+ case FS_TYPE_NEGOPT:
+ if (opt_in_list(cp, fs->opts))
+ return 0;
+ break;
+ case FS_TYPE_OPT:
+ if (!opt_in_list(cp, fs->opts))
+ return 0;
+ break;
+ }
+ }
+ if (checked_type == 0)
+ return 1;
+ return (cmp->negate ? !ret : ret);
+}
+
+/* Check if we should ignore this filesystem. */
+static int ignore(struct fs_info *fs)
+{
+ const char **ip;
+ int wanted = 0;
+
+ /*
+ * If the pass number is 0, ignore it.
+ */
+ if (fs->passno == 0)
+ return 1;
+
+ /*
+ * If this is a bind mount, ignore it.
+ */
+ if (opt_in_list("bind", fs->opts)) {
+ fprintf(stderr,
+ _("%s: skipping bad line in /etc/fstab: bind mount with nonzero fsck pass number\n"),
+ fs->mountpt);
+ return 1;
+ }
+
+ interpret_type(fs);
+
+ /*
+ * If a specific fstype is specified, and it doesn't match,
+ * ignore it.
+ */
+ if (!fs_match(fs, &fs_type_compiled)) return 1;
+
+ /* Are we ignoring this type? */
+ for(ip = ignored_types; *ip; ip++)
+ if (strcmp(fs->type, *ip) == 0) return 1;
+
+ /* Do we really really want to check this fs? */
+ for(ip = really_wanted; *ip; ip++)
+ if (strcmp(fs->type, *ip) == 0) {
+ wanted = 1;
+ break;
+ }
+
+ /* See if the <fsck.fs> program is available. */
+ if (find_fsck(fs->type) == NULL) {
+ if (wanted)
+ fprintf(stderr, _("fsck: cannot check %s: fsck.%s not found\n"),
+ fs->device, fs->type);
+ return 1;
+ }
+
+ /* We can and want to check this file system type. */
+ return 0;
+}
+
+/*
+ * Returns TRUE if a partition on the same disk is already being
+ * checked.
+ */
+static int device_already_active(char *device)
+{
+ struct fsck_instance *inst;
+ char *base;
+
+ if (force_all_parallel)
+ return 0;
+
+#ifdef BASE_MD
+ /* Don't check a soft raid disk with any other disk */
+ if (instance_list &&
+ (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) ||
+ !strncmp(device, BASE_MD, sizeof(BASE_MD)-1)))
+ return 1;
+#endif
+
+ base = base_device(device);
+ /*
+ * If we don't know the base device, assume that the device is
+ * already active if there are any fsck instances running.
+ */
+ if (!base)
+ return (instance_list != 0);
+ for (inst = instance_list; inst; inst = inst->next) {
+ if (!inst->base_device || !strcmp(base, inst->base_device)) {
+ free(base);
+ return 1;
+ }
+ }
+ free(base);
+ return 0;
+}
+
+/* Check all file systems, using the /etc/fstab table. */
+static int check_all(NOARGS)
+{
+ struct fs_info *fs = NULL;
+ int status = EXIT_OK;
+ int not_done_yet = 1;
+ int passno = 1;
+ int pass_done;
+
+ if (verbose)
+ fputs(_("Checking all file systems.\n"), stdout);
+
+ /*
+ * Do an initial scan over the filesystem; mark filesystems
+ * which should be ignored as done, and resolve any "auto"
+ * filesystem types (done as a side-effect of calling ignore()).
+ */
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (ignore(fs))
+ fs->flags |= FLAG_DONE;
+ }
+
+ /*
+ * Find and check the root filesystem.
+ */
+ if (!parallel_root) {
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (!strcmp(fs->mountpt, "/"))
+ break;
+ }
+ if (fs) {
+ if (!skip_root && !ignore(fs) &&
+ !(ignore_mounted && is_mounted(fs->device))) {
+ fsck_device(fs, 1);
+ status |= wait_many(FLAG_WAIT_ALL);
+ if (status > EXIT_NONDESTRUCT)
+ return status;
+ }
+ fs->flags |= FLAG_DONE;
+ }
+ }
+ /*
+ * This is for the bone-headed user who enters the root
+ * filesystem twice. Skip root will skep all root entries.
+ */
+ if (skip_root)
+ for (fs = filesys_info; fs; fs = fs->next)
+ if (!strcmp(fs->mountpt, "/"))
+ fs->flags |= FLAG_DONE;
+
+ while (not_done_yet) {
+ not_done_yet = 0;
+ pass_done = 1;
+
+ for (fs = filesys_info; fs; fs = fs->next) {
+ if (cancel_requested)
+ break;
+ if (fs->flags & FLAG_DONE)
+ continue;
+ /*
+ * If the filesystem's pass number is higher
+ * than the current pass number, then we don't
+ * do it yet.
+ */
+ if (fs->passno > passno) {
+ not_done_yet++;
+ continue;
+ }
+ if (ignore_mounted && is_mounted(fs->device)) {
+ fs->flags |= FLAG_DONE;
+ continue;
+ }
+ /*
+ * If a filesystem on a particular device has
+ * already been spawned, then we need to defer
+ * this to another pass.
+ */
+ if (device_already_active(fs->device)) {
+ pass_done = 0;
+ continue;
+ }
+ /*
+ * Spawn off the fsck process
+ */
+ fsck_device(fs, serialize);
+ fs->flags |= FLAG_DONE;
+
+ /*
+ * Only do one filesystem at a time, or if we
+ * have a limit on the number of fsck's extant
+ * at one time, apply that limit.
+ */
+ if (serialize ||
+ (max_running && (num_running >= max_running))) {
+ pass_done = 0;
+ break;
+ }
+ }
+ if (cancel_requested)
+ break;
+ if (verbose > 1)
+ printf(_("--waiting-- (pass %d)\n"), passno);
+ status |= wait_many(pass_done ? FLAG_WAIT_ALL :
+ FLAG_WAIT_ATLEAST_ONE);
+ if (pass_done) {
+ if (verbose > 1)
+ printf("----------------------------------\n");
+ passno++;
+ } else
+ not_done_yet++;
+ }
+ if (cancel_requested && !kill_sent) {
+ kill_all(SIGTERM);
+ kill_sent++;
+ }
+ status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
+ return status;
+}
+
+static void usage(NOARGS)
+{
+ fputs(_("Usage: fsck [-AMNPRTV] [ -C [ fd ] ] [-t fstype] [fs-options] [filesys ...]\n"), stderr);
+ exit(EXIT_USAGE);
+}
+
+#ifdef HAVE_SIGNAL_H
+static void signal_cancel(int sig FSCK_ATTR((unused)))
+{
+ cancel_requested++;
+}
+#endif
+
+static void PRS(int argc, char *argv[])
+{
+ int i, j;
+ char *arg, *dev, *tmp = 0;
+ char options[128];
+ int opt = 0;
+ int opts_for_fsck = 0;
+#ifdef HAVE_SIGNAL_H
+ struct sigaction sa;
+
+ /*
+ * Set up signal action
+ */
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_handler = signal_cancel;
+ sigaction(SIGINT, &sa, 0);
+ sigaction(SIGTERM, &sa, 0);
+#endif
+
+ num_devices = 0;
+ num_args = 0;
+ instance_list = 0;
+
+ progname = argv[0];
+
+ for (i=1; i < argc; i++) {
+ arg = argv[i];
+ if (!arg)
+ continue;
+ if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
+ if (num_devices >= MAX_DEVICES) {
+ fprintf(stderr, _("%s: too many devices\n"),
+ progname);
+ exit(EXIT_ERROR);
+ }
+ dev = blkid_get_devname(cache, arg, NULL);
+ if (!dev && strchr(arg, '=')) {
+ /*
+ * Check to see if we failed because
+ * /proc/partitions isn't found.
+ */
+ if (access("/proc/partitions", R_OK) < 0) {
+ fprintf(stderr, "Couldn't open /proc/partitions: %s\n",
+ strerror(errno));
+ fprintf(stderr, "Is /proc mounted?\n");
+ exit(EXIT_ERROR);
+ }
+ /*
+ * Check to see if this is because
+ * we're not running as root
+ */
+ if (geteuid())
+ fprintf(stderr,
+ "Must be root to scan for matching filesystems: %s\n", arg);
+ else
+ fprintf(stderr,
+ "Couldn't find matching filesystem: %s\n", arg);
+ exit(EXIT_ERROR);
+ }
+ devices[num_devices++] = dev ? dev : string_copy(arg);
+ continue;
+ }
+ if (arg[0] != '-' || opts_for_fsck) {
+ if (num_args >= MAX_ARGS) {
+ fprintf(stderr, _("%s: too many arguments\n"),
+ progname);
+ exit(EXIT_ERROR);
+ }
+ args[num_args++] = string_copy(arg);
+ continue;
+ }
+ for (j=1; arg[j]; j++) {
+ if (opts_for_fsck) {
+ options[++opt] = arg[j];
+ continue;
+ }
+ switch (arg[j]) {
+ case 'A':
+ doall++;
+ break;
+ case 'C':
+ progress++;
+ if (arg[j+1]) {
+ progress_fd = string_to_int(arg+j+1);
+ if (progress_fd < 0)
+ progress_fd = 0;
+ else
+ goto next_arg;
+ } else if ((i+1) < argc &&
+ !strncmp(argv[i+1], "-", 1) == 0) {
+ progress_fd = string_to_int(argv[i]);
+ if (progress_fd < 0)
+ progress_fd = 0;
+ else {
+ ++i;
+ goto next_arg;
+ }
+ }
+ break;
+ case 'V':
+ verbose++;
+ break;
+ case 'N':
+ noexecute++;
+ break;
+ case 'R':
+ skip_root++;
+ break;
+ case 'T':
+ notitle++;
+ break;
+ case 'M':
+ ignore_mounted++;
+ break;
+ case 'P':
+ parallel_root++;
+ break;
+ case 's':
+ serialize++;
+ break;
+ case 't':
+ tmp = 0;
+ if (fstype)
+ usage();
+ if (arg[j+1])
+ tmp = arg+j+1;
+ else if ((i+1) < argc)
+ tmp = argv[++i];
+ else
+ usage();
+ fstype = string_copy(tmp);
+ compile_fs_type(fstype, &fs_type_compiled);
+ goto next_arg;
+ case '-':
+ opts_for_fsck++;
+ break;
+ case '?':
+ usage();
+ break;
+ default:
+ options[++opt] = arg[j];
+ break;
+ }
+ }
+ next_arg:
+ if (opt) {
+ options[0] = '-';
+ options[++opt] = '\0';
+ if (num_args >= MAX_ARGS) {
+ fprintf(stderr,
+ _("%s: too many arguments\n"),
+ progname);
+ exit(EXIT_ERROR);
+ }
+ args[num_args++] = string_copy(options);
+ opt = 0;
+ }
+ }
+ if (getenv("FSCK_FORCE_ALL_PARALLEL"))
+ force_all_parallel++;
+ if ((tmp = getenv("FSCK_MAX_INST")))
+ max_running = atoi(tmp);
+}
+
+int main(int argc, char *argv[])
+{
+ int i, status = 0;
+ int interactive = 0;
+ char *oldpath = getenv("PATH");
+ const char *fstab;
+ struct fs_info *fs;
+
+ setvbuf(stdout, NULL, _IONBF, BUFSIZ);
+ setvbuf(stderr, NULL, _IONBF, BUFSIZ);
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+#endif
+ blkid_get_cache(&cache, NULL);
+ PRS(argc, argv);
+
+ if (!notitle)
+ printf("fsck %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
+
+ fstab = getenv("FSTAB_FILE");
+ if (!fstab)
+ fstab = _PATH_MNTTAB;
+ load_fs_info(fstab);
+
+ /* Update our search path to include uncommon directories. */
+ if (oldpath) {
+ fsck_path = malloc (strlen (fsck_prefix_path) + 1 +
+ strlen (oldpath) + 1);
+ if (!fsck_path) {
+ fprintf(stderr, "%s: Unable to allocate memory for fsck_path\n", progname);
+ exit(EXIT_ERROR);
+ }
+ strcpy (fsck_path, fsck_prefix_path);
+ strcat (fsck_path, ":");
+ strcat (fsck_path, oldpath);
+ } else {
+ fsck_path = string_copy(fsck_prefix_path);
+ }
+
+ if ((num_devices == 1) || (serialize))
+ interactive = 1;
+
+ /* If -A was specified ("check all"), do that! */
+ if (doall)
+ return check_all();
+
+ if (num_devices == 0) {
+ serialize++;
+ interactive++;
+ return check_all();
+ }
+ for (i = 0 ; i < num_devices; i++) {
+ if (cancel_requested) {
+ if (!kill_sent) {
+ kill_all(SIGTERM);
+ kill_sent++;
+ }
+ break;
+ }
+ fs = lookup(devices[i]);
+ if (!fs) {
+ fs = create_fs_device(devices[i], 0, "auto",
+ 0, -1, -1);
+ if (!fs)
+ continue;
+ }
+ if (ignore_mounted && is_mounted(fs->device))
+ continue;
+ fsck_device(fs, interactive);
+ if (serialize ||
+ (max_running && (num_running >= max_running))) {
+ struct fsck_instance *inst;
+
+ inst = wait_one(0);
+ if (inst) {
+ status |= inst->exit_status;
+ free_instance(inst);
+ }
+ if (verbose > 1)
+ printf("----------------------------------\n");
+ }
+ }
+ status |= wait_many(FLAG_WAIT_ALL);
+ free(fsck_path);
+ blkid_put_cache(cache);
+ return status;
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/fsck.h b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/fsck.h
new file mode 100644
index 0000000..8a0f70e
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/fsck.h
@@ -0,0 +1,73 @@
+/*
+ * fsck.h
+ */
+
+#include <time.h>
+
+#ifdef __STDC__
+#define NOARGS void
+#else
+#define NOARGS
+#define const
+#endif
+
+#ifdef __GNUC__
+#define FSCK_ATTR(x) __attribute__(x)
+#else
+#define FSCK_ATTR(x)
+#endif
+
+
+#ifndef DEFAULT_FSTYPE
+#define DEFAULT_FSTYPE "ext2"
+#endif
+
+#define MAX_DEVICES 32
+#define MAX_ARGS 32
+
+#define EXIT_OK 0
+#define EXIT_NONDESTRUCT 1
+#define EXIT_DESTRUCT 2
+#define EXIT_UNCORRECTED 4
+#define EXIT_ERROR 8
+#define EXIT_USAGE 16
+#define EXIT_LIBRARY 128
+
+/*
+ * Internal structure for mount tabel entries.
+ */
+
+struct fs_info {
+ char *device;
+ char *mountpt;
+ char *type;
+ char *opts;
+ int freq;
+ int passno;
+ int flags;
+ struct fs_info *next;
+};
+
+#define FLAG_DONE 1
+#define FLAG_PROGRESS 2
+
+/*
+ * Structure to allow exit codes to be stored
+ */
+struct fsck_instance {
+ int pid;
+ int flags;
+ int exit_status;
+ time_t start_time;
+ char * prog;
+ char * type;
+ char * device;
+ char * base_device;
+ struct fsck_instance *next;
+};
+
+extern char *base_device(const char *device);
+extern const char *identify_fs(const char *fs_name, const char *fs_types);
+
+/* ismounted.h */
+extern int is_mounted(const char *file);
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/ismounted.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/ismounted.c
new file mode 100644
index 0000000..6aa0e04
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/ismounted.c
@@ -0,0 +1,218 @@
+/*
+ * ismounted.c --- Check to see if the filesystem was mounted
+ *
+ * Copyright (C) 1995,1996,1997,1998,1999,2000,2008 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_LINUX_FD_H
+#include <linux/fd.h>
+#endif
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+#include <string.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#include "fsck.h"
+
+/*
+ * ext2fs_check_if_mounted flags
+ */
+#define MF_MOUNTED 1
+
+#include "et/com_err.h"
+
+#ifdef HAVE_SETMNTENT
+static char *skip_over_blank(char *cp)
+{
+ while (*cp && isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static char *skip_over_word(char *cp)
+{
+ while (*cp && !isspace(*cp))
+ cp++;
+ return cp;
+}
+
+static char *parse_word(char **buf)
+{
+ char *word, *next;
+
+ word = *buf;
+ if (*word == 0)
+ return 0;
+
+ word = skip_over_blank(word);
+ next = skip_over_word(word);
+ if (*next)
+ *next++ = 0;
+ *buf = next;
+ return word;
+}
+#endif
+
+/*
+ * Helper function which checks a file in /etc/mtab format to see if a
+ * filesystem is mounted. Returns an error if the file doesn't exist
+ * or can't be opened.
+ */
+static errcode_t check_mntent_file(const char *mtab_file, const char *file,
+ int *mount_flags)
+{
+#ifdef HAVE_SETMNTENT
+ struct stat st_buf;
+ errcode_t retval = 0;
+ dev_t file_dev=0, file_rdev=0;
+ ino_t file_ino=0;
+ FILE *f;
+ char buf[1024], *device = 0, *mnt_dir = 0, *cp;
+
+ *mount_flags = 0;
+ if ((f = setmntent (mtab_file, "r")) == NULL)
+ return errno;
+ if (stat(file, &st_buf) == 0) {
+ if (S_ISBLK(st_buf.st_mode)) {
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+ file_rdev = st_buf.st_rdev;
+#endif /* __GNU__ */
+ } else {
+ file_dev = st_buf.st_dev;
+ file_ino = st_buf.st_ino;
+ }
+ }
+ while (1) {
+ if (!fgets(buf, sizeof(buf), f)) {
+ device = mnt_dir = 0;
+ break;
+ }
+ buf[sizeof(buf)-1] = 0;
+
+ cp = buf;
+ device = parse_word(&cp);
+ if (!device || *device == '#')
+ return 0; /* Ignore blank lines and comments */
+ mnt_dir = parse_word(&cp);
+
+ if (device[0] != '/')
+ continue;
+
+ if (strcmp(file, device) == 0)
+ break;
+ if (stat(device, &st_buf) == 0) {
+ if (S_ISBLK(st_buf.st_mode)) {
+#ifndef __GNU__
+ if (file_rdev && (file_rdev == st_buf.st_rdev))
+ break;
+#endif /* __GNU__ */
+ } else {
+ if (file_dev && ((file_dev == st_buf.st_dev) &&
+ (file_ino == st_buf.st_ino)))
+ break;
+ }
+ }
+ }
+
+ if (mnt_dir == 0) {
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+ /*
+ * Do an extra check to see if this is the root device. We
+ * can't trust /etc/mtab, and /proc/mounts will only list
+ * /dev/root for the root filesystem. Argh. Instead we
+ * check if the given device has the same major/minor number
+ * as the device that the root directory is on.
+ */
+ if (file_rdev && (stat("/", &st_buf) == 0) &&
+ (st_buf.st_dev == file_rdev))
+ *mount_flags = MF_MOUNTED;
+#endif /* __GNU__ */
+ goto errout;
+ }
+#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
+ /* Validate the entry in case /etc/mtab is out of date */
+ /*
+ * We need to be paranoid, because some broken distributions
+ * (read: Slackware) don't initialize /etc/mtab before checking
+ * all of the non-root filesystems on the disk.
+ */
+ if (stat(mnt_dir, &st_buf) < 0) {
+ retval = errno;
+ if (retval == ENOENT) {
+#ifdef DEBUG
+ printf("Bogus entry in %s! (%s does not exist)\n",
+ mtab_file, mnt_dir);
+#endif /* DEBUG */
+ retval = 0;
+ }
+ goto errout;
+ }
+ if (file_rdev && (st_buf.st_dev != file_rdev)) {
+#ifdef DEBUG
+ printf("Bogus entry in %s! (%s not mounted on %s)\n",
+ mtab_file, file, mnt_dir);
+#endif /* DEBUG */
+ goto errout;
+ }
+#endif /* __GNU__ */
+ *mount_flags = MF_MOUNTED;
+
+ retval = 0;
+errout:
+ endmntent (f);
+ return retval;
+#else /* !HAVE_SETMNTENT */
+ return 0;
+#endif /* HAVE_MNTENT_H */
+}
+
+int is_mounted(const char *file)
+{
+ errcode_t retval;
+ int mount_flags = 0;
+
+#ifdef __linux__
+ retval = check_mntent_file("/proc/mounts", file, &mount_flags);
+ if (retval)
+ return 0;
+ if (mount_flags)
+ return 1;
+#endif /* __linux__ */
+ retval = check_mntent_file("/etc/mtab", file, &mount_flags);
+ if (retval)
+ return 0;
+ return (mount_flags);
+}
+
+#ifdef DEBUG
+int main(int argc, char **argv)
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s device\n", argv[0]);
+ exit(1);
+ }
+
+ if (is_mounted(argv[1]))
+ printf("\t%s is mounted.\n", argv[1]);
+ exit(0);
+}
+#endif /* DEBUG */
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/jfs_user.h b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/jfs_user.h
new file mode 100644
index 0000000..3070cd5
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/jfs_user.h
@@ -0,0 +1,8 @@
+#ifndef _JFS_USER_H
+#define _JFS_USER_H
+
+typedef unsigned short kdev_t;
+
+#include <ext2fs/kernel-jbd.h>
+
+#endif /* _JFS_USER_H */
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/logsave.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/logsave.8.in
new file mode 100644
index 0000000..f0fbe41
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/logsave.8.in
@@ -0,0 +1,61 @@
+.\" -*- nroff -*-
+.\" Copyright 2003 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH LOGSAVE 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+logsave \- save the output of a command in a logfile
+.SH SYNOPSIS
+.B logsave
+[
+.B \-asv
+]
+.I logfile cmd_prog [ ... ]
+.SH DESCRIPTION
+The
+.B logsave
+program will execute
+.I cmd_prog
+with the specified argument(s), and save a copy of its output to
+.IR logfile .
+If the containing directory for
+.I logfile
+does not exist,
+.B logsave
+will accumulate the output in memory until it can be written out.
+A copy of the output will also be written to standard output.
+.PP
+If
+.I cmd_prog
+is a single hyphen ('-'), then instead of executing a program,
+.B logsave
+will take its input from standard input and save it in
+.I logfile
+.PP
+.B logsave
+is useful for saving the output of initial boot scripts
+until the /var partition is mounted, so the output can be written to
+/var/log.
+.SH OPTIONS
+.TP
+.B \-a
+This option will cause the output to be appended to
+.IR logfile ,
+instead of replacing its current contents.
+.TP
+.B \-s
+This option will cause
+.B logsave
+to skip writing to the log file text which is bracketed with a control-A
+(ASCII 001 or Start of Header) and control-B (ASCII 002 or Start of
+Text). This allows progress bar information to be visible to the user
+on the console, while not being written to the log file.
+.TP
+.B \-v
+This option will make
+.B logsave
+to be more verbose in its output to the user.
+.SH AUTHOR
+Theodore Ts'o (tytso@mit.edu)
+.SH SEE ALSO
+.BR fsck (8)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/logsave.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/logsave.c
new file mode 100644
index 0000000..8612edf
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/logsave.c
@@ -0,0 +1,334 @@
+/*
+ * logsave.c --- A program which saves the output of a program until
+ * /var/log is mounted.
+ *
+ * Copyright (C) 2003 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+
+static int outfd = -1;
+static int outbufsize = 0;
+static void *outbuf = 0;
+static int verbose = 0;
+static int do_skip = 0;
+static int skip_mode = 0;
+static pid_t child_pid = -1;
+
+static void usage(char *progname)
+{
+ printf("Usage: %s [-asv] logfile program\n", progname);
+ exit(1);
+}
+
+#define SEND_LOG 0x01
+#define SEND_CONSOLE 0x02
+#define SEND_BOTH 0x03
+
+/*
+ * Helper function that does the right thing if write returns a
+ * partial write, or an EGAIN/EINTR error.
+ */
+static int write_all(int fd, const char *buf, size_t count)
+{
+ ssize_t ret;
+ int c = 0;
+
+ while (count > 0) {
+ ret = write(fd, buf, count);
+ if (ret < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ return -1;
+ }
+ count -= ret;
+ buf += ret;
+ c += ret;
+ }
+ return c;
+}
+
+static void send_output(const char *buffer, int c, int flag)
+{
+ const char *cp;
+ char *n;
+ int cnt, d, del;
+
+ if (c == 0)
+ c = strlen(buffer);
+
+ if (flag & SEND_CONSOLE) {
+ cnt = c;
+ cp = buffer;
+ while (cnt) {
+ del = 0;
+ for (d=0; d < cnt; d++) {
+ if (skip_mode &&
+ (cp[d] == '\001' || cp[d] == '\002')) {
+ del = 1;
+ break;
+ }
+ }
+ write_all(1, cp, d);
+ if (del)
+ d++;
+ cnt -= d;
+ cp += d;
+ }
+ }
+ if (!(flag & SEND_LOG))
+ return;
+ if (outfd > 0)
+ write_all(outfd, buffer, c);
+ else {
+ n = realloc(outbuf, outbufsize + c);
+ if (n) {
+ outbuf = n;
+ memcpy(((char *)outbuf)+outbufsize, buffer, c);
+ outbufsize += c;
+ }
+ }
+}
+
+static int do_read(int fd)
+{
+ int c;
+ char buffer[4096], *cp, *sep;
+
+ c = read(fd, buffer, sizeof(buffer)-1);
+ if (c <= 0)
+ return c;
+ if (do_skip) {
+ send_output(buffer, c, SEND_CONSOLE);
+ buffer[c] = 0;
+ cp = buffer;
+ while (*cp) {
+ if (skip_mode) {
+ cp = strchr(cp, '\002');
+ if (!cp)
+ return 0;
+ cp++;
+ skip_mode = 0;
+ continue;
+ }
+ sep = strchr(cp, '\001');
+ if (sep)
+ *sep = 0;
+ send_output(cp, 0, SEND_LOG);
+ if (sep) {
+ cp = sep + 1;
+ skip_mode = 1;
+ } else
+ break;
+ }
+ } else
+ send_output(buffer, c, SEND_BOTH);
+ return c;
+}
+
+static void signal_term(int sig)
+{
+ if (child_pid > 0)
+ kill(child_pid, sig);
+}
+
+static int run_program(char **argv)
+{
+ int fds[2];
+ int status, rc, pid;
+ char buffer[80];
+#ifdef HAVE_SIGNAL_H
+ struct sigaction sa;
+#endif
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ exit(1);
+ }
+
+#ifdef HAVE_SIGNAL_H
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_handler = signal_term;
+ sigaction(SIGINT, &sa, 0);
+ sigaction(SIGTERM, &sa, 0);
+#ifdef SA_RESTART
+ sa.sa_flags = SA_RESTART;
+#endif
+#endif
+
+ pid = fork();
+ if (pid < 0) {
+ perror("vfork");
+ exit(1);
+ }
+ if (pid == 0) {
+ dup2(fds[1],1); /* fds[1] replaces stdout */
+ dup2(fds[1],2); /* fds[1] replaces stderr */
+ close(fds[0]); /* don't need this here */
+ close(fds[1]);
+
+ execvp(argv[0], argv);
+ perror(argv[0]);
+ exit(1);
+ }
+ child_pid = pid;
+ close(fds[1]);
+
+ while (!(waitpid(pid, &status, WNOHANG ))) {
+ do_read(fds[0]);
+ }
+ child_pid = -1;
+ do_read(fds[0]);
+ close(fds[0]);
+
+ if ( WIFEXITED(status) ) {
+ rc = WEXITSTATUS(status);
+ if (rc) {
+ send_output(argv[0], 0, SEND_BOTH);
+ sprintf(buffer, " died with exit status %d\n", rc);
+ send_output(buffer, 0, SEND_BOTH);
+ }
+ } else {
+ if (WIFSIGNALED(status)) {
+ send_output(argv[0], 0, SEND_BOTH);
+ sprintf(buffer, "died with signal %d\n",
+ WTERMSIG(status));
+ send_output(buffer, 0, SEND_BOTH);
+ rc = 1;
+ }
+ rc = 0;
+ }
+ return rc;
+}
+
+static int copy_from_stdin(void)
+{
+ int c, bad_read = 0;
+
+ while (1) {
+ c = do_read(0);
+ if ((c == 0 ) ||
+ ((c < 0) && ((errno == EAGAIN) || (errno == EINTR)))) {
+ if (bad_read++ > 3)
+ break;
+ continue;
+ }
+ if (c < 0) {
+ perror("read");
+ exit(1);
+ }
+ bad_read = 0;
+ }
+ return 0;
+}
+
+
+
+int main(int argc, char **argv)
+{
+ int c, pid, rc;
+ char *outfn, **cpp;
+ int openflags = O_CREAT|O_WRONLY|O_TRUNC;
+ int send_flag = SEND_LOG;
+ int do_stdin;
+ time_t t;
+
+ while ((c = getopt(argc, argv, "+asv")) != EOF) {
+ switch (c) {
+ case 'a':
+ openflags &= ~O_TRUNC;
+ openflags |= O_APPEND;
+ break;
+ case 's':
+ do_skip = 1;
+ break;
+ case 'v':
+ verbose++;
+ send_flag |= SEND_CONSOLE;
+ break;
+ }
+ }
+ if (optind == argc || optind+1 == argc)
+ usage(argv[0]);
+ outfn = argv[optind];
+ optind++;
+ argv += optind;
+ argc -= optind;
+
+ outfd = open(outfn, openflags, 0644);
+ do_stdin = !strcmp(argv[0], "-");
+
+ send_output("Log of ", 0, send_flag);
+ if (do_stdin)
+ send_output("stdin", 0, send_flag);
+ else {
+ for (cpp = argv; *cpp; cpp++) {
+ send_output(*cpp, 0, send_flag);
+ send_output(" ", 0, send_flag);
+ }
+ }
+ send_output("\n", 0, send_flag);
+ t = time(0);
+ send_output(ctime(&t), 0, send_flag);
+ send_output("\n", 0, send_flag);
+
+ if (do_stdin)
+ rc = copy_from_stdin();
+ else
+ rc = run_program(argv);
+
+ send_output("\n", 0, send_flag);
+ t = time(0);
+ send_output(ctime(&t), 0, send_flag);
+ send_output("----------------\n", 0, send_flag);
+
+ if (outbuf) {
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ exit(1);
+ }
+ if (pid) {
+ if (verbose)
+ printf("Backgrounding to save %s later\n",
+ outfn);
+ exit(rc);
+ }
+ setsid(); /* To avoid getting killed by init */
+ while (outfd < 0) {
+ outfd = open(outfn, openflags, 0644);
+ sleep(1);
+ }
+ write_all(outfd, outbuf, outbufsize);
+ free(outbuf);
+ }
+ if (outfd >= 0)
+ close(outfd);
+
+ exit(rc);
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/lsattr.1.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/lsattr.1.in
new file mode 100644
index 0000000..7798a34
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/lsattr.1.in
@@ -0,0 +1,45 @@
+.\" -*- nroff -*-
+.TH LSATTR 1 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+lsattr \- list file attributes on a Linux second extended file system
+.SH SYNOPSIS
+.B lsattr
+[
+.B \-RVadv
+]
+[
+.I files...
+]
+.SH DESCRIPTION
+.B lsattr
+lists the file attributes on a second extended file system. See
+.BR chattr (1)
+for a description of the attributes and what they mean.
+.SH OPTIONS
+.TP
+.B \-R
+Recursively list attributes of directories and their contents.
+.TP
+.B \-V
+Display the program version.
+.TP
+.B \-a
+List all files in directories, including files that start with `.'.
+.TP
+.B \-d
+List directories like other files, rather than listing their contents.
+.TP
+.B \-v
+List the file's version/generation number.
+.SH AUTHOR
+.B lsattr
+was written by Remy Card <Remy.Card@linux.org>. It is currently being
+maintained by Theodore Ts'o <tytso@alum.mit.edu>.
+.SH BUGS
+There are none :-).
+.SH AVAILABILITY
+.B lsattr
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR chattr (1)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/lsattr.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/lsattr.c
new file mode 100644
index 0000000..e5e5969
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/lsattr.c
@@ -0,0 +1,213 @@
+/*
+ * lsattr.c - List file attributes on an ext2 file system
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30 - Creation
+ * 93/11/13 - Replace stat() calls by lstat() to avoid loops
+ * 94/02/27 - Integrated in Ted's distribution
+ * 98/12/29 - Display version info only when -V specified (G M Sipe)
+ */
+
+#define _LARGEFILE64_SOURCE
+
+#include "config.h"
+#include <sys/types.h>
+#include <dirent.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern int optind;
+extern char *optarg;
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include "ext2fs/ext2_fs.h"
+#include "et/com_err.h"
+#include "e2p/e2p.h"
+
+#include "../version.h"
+#include "nls-enable.h"
+
+#ifdef __GNUC__
+#define EXT2FS_ATTR(x) __attribute__(x)
+#else
+#define EXT2FS_ATTR(x)
+#endif
+
+static const char * program_name = "lsattr";
+
+static int all;
+static int dirs_opt;
+static unsigned pf_options;
+static int recursive;
+static int verbose;
+static int generation_opt;
+
+#ifdef _LFS64_LARGEFILE
+#define LSTAT lstat64
+#define STRUCT_STAT struct stat64
+#else
+#define LSTAT lstat
+#define STRUCT_STAT struct stat
+#endif
+
+static void usage(void)
+{
+ fprintf(stderr, _("Usage: %s [-RVadlv] [files...]\n"), program_name);
+ exit(1);
+}
+
+static int list_attributes (const char * name)
+{
+ unsigned long flags;
+ unsigned long generation;
+
+ if (fgetflags (name, &flags) == -1) {
+ com_err (program_name, errno, _("While reading flags on %s"),
+ name);
+ return -1;
+ }
+ if (generation_opt) {
+ if (fgetversion (name, &generation) == -1) {
+ com_err (program_name, errno,
+ _("While reading version on %s"),
+ name);
+ return -1;
+ }
+ printf ("%5lu ", generation);
+ }
+ if (pf_options & PFOPT_LONG) {
+ printf("%-28s ", name);
+ print_flags(stdout, flags, pf_options);
+ fputc('\n', stdout);
+ } else {
+ print_flags(stdout, flags, pf_options);
+ printf(" %s\n", name);
+ }
+ return 0;
+}
+
+static int lsattr_dir_proc (const char *, struct dirent *, void *);
+
+static int lsattr_args (const char * name)
+{
+ STRUCT_STAT st;
+ int retval = 0;
+
+ if (LSTAT (name, &st) == -1) {
+ com_err (program_name, errno, _("while trying to stat %s"),
+ name);
+ retval = -1;
+ } else {
+ if (S_ISDIR(st.st_mode) && !dirs_opt)
+ retval = iterate_on_dir (name, lsattr_dir_proc, NULL);
+ else
+ retval = list_attributes (name);
+ }
+ return retval;
+}
+
+static int lsattr_dir_proc (const char * dir_name, struct dirent * de,
+ void * private EXT2FS_ATTR((unused)))
+{
+ STRUCT_STAT st;
+ char *path;
+ int dir_len = strlen(dir_name);
+
+ path = malloc(dir_len + strlen (de->d_name) + 2);
+
+ if (dir_len && dir_name[dir_len-1] == '/')
+ sprintf (path, "%s%s", dir_name, de->d_name);
+ else
+ sprintf (path, "%s/%s", dir_name, de->d_name);
+ if (LSTAT (path, &st) == -1)
+ perror (path);
+ else {
+ if (de->d_name[0] != '.' || all) {
+ list_attributes (path);
+ if (S_ISDIR(st.st_mode) && recursive &&
+ strcmp(de->d_name, ".") &&
+ strcmp(de->d_name, "..")) {
+ printf ("\n%s:\n", path);
+ iterate_on_dir (path, lsattr_dir_proc, NULL);
+ printf ("\n");
+ }
+ }
+ }
+ free(path);
+ return 0;
+}
+
+int main (int argc, char ** argv)
+{
+ int c;
+ int i;
+ int err, retval = 0;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+ if (argc && *argv)
+ program_name = *argv;
+ while ((c = getopt (argc, argv, "RVadlv")) != EOF)
+ switch (c)
+ {
+ case 'R':
+ recursive = 1;
+ break;
+ case 'V':
+ verbose = 1;
+ break;
+ case 'a':
+ all = 1;
+ break;
+ case 'd':
+ dirs_opt = 1;
+ break;
+ case 'l':
+ pf_options = PFOPT_LONG;
+ break;
+ case 'v':
+ generation_opt = 1;
+ break;
+ default:
+ usage();
+ }
+
+ if (verbose)
+ fprintf (stderr, "lsattr %s (%s)\n",
+ E2FSPROGS_VERSION, E2FSPROGS_DATE);
+ if (optind > argc - 1) {
+ if (lsattr_args (".") == -1)
+ retval = 1;
+ } else {
+ for (i = optind; i < argc; i++) {
+ err = lsattr_args (argv[i]);
+ if (err)
+ retval = 1;
+ }
+ }
+ exit(retval);
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs-hurd.conf b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs-hurd.conf
new file mode 100644
index 0000000..4f0527d
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs-hurd.conf
@@ -0,0 +1,42 @@
+[defaults]
+ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr
+ default_mntopts = acl,user_xattr
+ enable_periodic_fsck = 0
+ blocksize = 4096
+ inode_size = 128
+ inode_ratio = 16384
+
+[fs_types]
+ ext3 = {
+ features = has_journal
+ }
+ ext4 = {
+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize
+ auto_64-bit_support = 1
+ inode_size = 256
+ }
+ small = {
+ inode_ratio = 4096
+ }
+ floppy = {
+ inode_ratio = 8192
+ }
+ big = {
+ inode_ratio = 32768
+ }
+ huge = {
+ inode_ratio = 65536
+ }
+ news = {
+ inode_ratio = 4096
+ }
+ largefile = {
+ inode_ratio = 1048576
+ }
+ largefile4 = {
+ inode_ratio = 4194304
+ }
+ hurd = {
+ blocksize = 4096
+ inode_size = 128
+ }
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.8.in
new file mode 100644
index 0000000..fea50da
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.8.in
@@ -0,0 +1,700 @@
+.\" -*- nroff -*-
+.\" Copyright 1993, 1994, 1995 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH MKE2FS 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+mke2fs \- create an ext2/ext3/ext4 filesystem
+.SH SYNOPSIS
+.B mke2fs
+[
+.B \-c
+|
+.B \-l
+.I filename
+]
+[
+.B \-b
+.I block-size
+]
+[
+.B \-D
+]
+[
+.B \-f
+.I fragment-size
+]
+[
+.B \-g
+.I blocks-per-group
+]
+[
+.B \-G
+.I number-of-groups
+]
+[
+.B \-i
+.I bytes-per-inode
+]
+[
+.B \-I
+.I inode-size
+]
+[
+.B \-j
+]
+[
+.B \-J
+.I journal-options
+]
+[
+.B \-N
+.I number-of-inodes
+]
+[
+.B \-n
+]
+[
+.B \-m
+.I reserved-blocks-percentage
+]
+[
+.B \-o
+.I creator-os
+]
+[
+.B \-O
+.IR feature [,...]
+]
+[
+.B \-q
+]
+[
+.B \-r
+.I fs-revision-level
+]
+[
+.B \-E
+.I extended-options
+]
+[
+.B \-v
+]
+[
+.B \-F
+]
+[
+.B \-L
+.I volume-label
+]
+[
+.B \-M
+.I last-mounted-directory
+]
+[
+.B \-S
+]
+[
+.B \-t
+.I fs-type
+]
+[
+.B \-T
+.I usage-type
+]
+[
+.B \-U
+.I UUID
+]
+[
+.B \-V
+]
+.I device
+[
+.I blocks-count
+]
+@JDEV@.sp
+@JDEV@.B "mke2fs \-O journal_dev"
+@JDEV@[
+@JDEV@.B \-b
+@JDEV@.I block-size
+@JDEV@]
+.\" No external-journal specific journal options yet (size is ignored)
+.\" @JDEV@[
+.\" @JDEV@.B \-J
+.\" @JDEV@.I journal-options
+.\" @JDEV@]
+@JDEV@[
+@JDEV@.B \-L
+@JDEV@.I volume-label
+@JDEV@]
+@JDEV@[
+@JDEV@.B \-n
+@JDEV@]
+@JDEV@[
+@JDEV@.B \-q
+@JDEV@]
+@JDEV@[
+@JDEV@.B \-v
+@JDEV@]
+@JDEV@.I external-journal
+@JDEV@[
+@JDEV@.I blocks-count
+@JDEV@]
+.SH DESCRIPTION
+.B mke2fs
+is used to create an ext2, ext3, or ext4 filesystem, usually in a disk
+partition.
+.I device
+is the special file corresponding to the device (e.g
+.IR /dev/hdXX ).
+.I blocks-count
+is the number of blocks on the device. If omitted,
+.B mke2fs
+automagically figures the file system size. If called as
+.B mkfs.ext3
+a journal is created as if the
+.B \-j
+option was specified.
+.PP
+The defaults of the parameters for the newly created filesystem, if not
+overridden by the options listed below, are controlled by the
+.B /etc/mke2fs.conf
+configuration file. See the
+.BR mke2fs.conf (5)
+manual page for more details.
+.SH OPTIONS
+.TP
+.BI \-b " block-size"
+Specify the size of blocks in bytes. Valid block-size values are 1024,
+2048 and 4096 bytes per block. If omitted,
+block-size is heuristically determined by the filesystem size and
+the expected usage of the filesystem (see the
+.B \-T
+option). If
+.I block-size
+is preceded by a negative sign ('-'), then
+.B mke2fs
+will use heuristics to determine the
+appropriate block size, with the constraint that the block size will be
+at least
+.I block-size
+bytes. This is useful for certain hardware devices which require that
+the blocksize be a multiple of 2k.
+.TP
+.B \-c
+Check the device for bad blocks before creating the file system. If
+this option is specified twice, then a slower read-write
+test is used instead of a fast read-only test.
+.TP
+.B \-C " cluster-size"
+Specify the size of cluster in bytes for filesystems using the bigalloc
+feature. Valid cluster-size values are from 2048 to 256M bytes per
+cluster. This can only be specified if the bigalloc feature is
+enabled. (See the
+.B ext4 (5)
+man page for more details about bigalloc.) The default cluster size if
+bigalloc is enabled is 16 times the block size.
+.TP
+.B \-D
+Use direct I/O when writing to the disk. This avoids mke2fs dirtying a
+lot of buffer cache memory, which may impact other applications running
+on a busy server. This option will cause mke2fs to run much more
+slowly, however, so there is a tradeoff to using direct I/O.
+.TP
+.BI \-E " extended-options"
+Set extended options for the filesystem. Extended options are comma
+separated, and may take an argument using the equals ('=') sign. The
+.B \-E
+option used to be
+.B \-R
+in earlier versions of
+.BR mke2fs .
+The
+.B \-R
+option is still accepted for backwards compatibility, but is deprecated.
+The following extended options are supported:
+.RS 1.2i
+.TP
+.BI mmp_update_interval= interval
+Adjust the initial MMP update interval to
+.I interval
+seconds. Specifying an
+.I interval
+of 0 means to use the default interval. The specified interval must
+be less than 300 seconds. Requires that the
+.B mmp
+feature be enabled.
+.TP
+.BI stride= stride-size
+Configure the filesystem for a RAID array with
+.I stride-size
+filesystem blocks. This is the number of blocks read or written to disk
+before moving to the next disk, which is sometimes referred to as the
+.I chunk size.
+This mostly affects placement of filesystem metadata like bitmaps at
+.B mke2fs
+time to avoid placing them on a single disk, which can hurt performance.
+It may also be used by the block allocator.
+.TP
+.BI stripe_width= stripe-width
+Configure the filesystem for a RAID array with
+.I stripe-width
+filesystem blocks per stripe. This is typically stride-size * N, where
+N is the number of data-bearing disks in the RAID (e.g. for RAID 5 there is one
+parity disk, so N will be the number of disks in the array minus 1).
+This allows the block allocator to prevent read-modify-write of the
+parity in a RAID stripe if possible when the data is written.
+.TP
+.BI resize= max-online-resize
+Reserve enough space so that the block group descriptor table can grow
+to support a filesystem that has
+.I max-online-resize
+blocks.
+.TP
+.B lazy_itable_init\fR[\fB= \fI<0 to disable, 1 to enable>\fR]
+If enabled and the uninit_bg feature is enabled, the inode table will
+not be fully initialized by
+.BR mke2fs .
+This speeds up filesystem
+initialization noticeably, but it requires the kernel to finish
+initializing the filesystem in the background when the filesystem is
+first mounted. If the option value is omitted, it defaults to 1 to
+enable lazy inode table zeroing.
+.TP
+.B lazy_journal_init\fR[\fB= \fI<0 to disable, 1 to enable>\fR]
+If enabled, the journal inode will not be fully zeroed out by
+.BR mke2fs .
+This speeds up filesystem initialization noticeably, but carries some
+small risk if the system crashes before the journal has been overwritten
+entirely one time. If the option value is omitted, it defaults to 1 to
+enable lazy journal inode zeroing.
+.TP
+.BI root_owner [=uid:gid]
+Specify the numeric user and group ID of the root directory. If no UID:GID
+is specified, use the user and group ID of the user running \fBmke2fs\fR.
+In \fBmke2fs\fR 1.42 and earlier the UID and GID of the root directory were
+set by default to the UID and GID of the user running the mke2fs command.
+The \fBroot_owner=\fR option allows explicitly specifying these values,
+and avoid side-effects for users that do not expect the contents of the
+filesystem to change based on the user running \fBmke2fs\fR.
+.TP
+.B test_fs
+Set a flag in the filesystem superblock indicating that it may be
+mounted using experimental kernel code, such as the ext4dev filesystem.
+.TP
+.BI discard
+Attempt to discard blocks at mkfs time (discarding blocks initially is useful
+on solid state devices and sparse / thin-provisioned storage). When the device
+advertises that discard also zeroes data (any subsequent read after the discard
+and before write returns zero), then mark all not-yet-zeroed inode tables as
+zeroed. This significantly speeds up filesystem initialization. This is set
+as default.
+.TP
+.BI nodiscard
+Do not attempt to discard blocks at mkfs time.
+@QUOTA_MAN_COMMENT@.TP
+@QUOTA_MAN_COMMENT@.BI quotatype
+@QUOTA_MAN_COMMENT@Specify which quota type ('usr' or 'grp') is to be
+@QUOTA_MAN_COMMENT@initialized. This option has effect only if the
+@QUOTA_MAN_COMMENT@.B quota
+@QUOTA_MAN_COMMENT@feature is set. Without this extended option, the default
+@QUOTA_MAN_COMMENT@behavior is to initialize both user and group quotas.
+.RE
+.TP
+.BI \-f " fragment-size"
+Specify the size of fragments in bytes.
+.TP
+.B \-F
+Force
+.B mke2fs
+to create a filesystem, even if the specified device is not a partition
+on a block special device, or if other parameters do not make sense.
+In order to force
+.B mke2fs
+to create a filesystem even if the filesystem appears to be in use
+or is mounted (a truly dangerous thing to do), this option must be
+specified twice.
+.TP
+.BI \-g " blocks-per-group"
+Specify the number of blocks in a block group. There is generally no
+reason for the user to ever set this parameter, as the default is optimal
+for the filesystem. (For administrators who are creating
+filesystems on RAID arrays, it is preferable to use the
+.I stride
+RAID parameter as part of the
+.B \-E
+option rather than manipulating the number of blocks per group.)
+This option is generally used by developers who
+are developing test cases.
+.IP
+If the bigalloc feature is enabled, the
+.B \-g
+option will specify the number of clusters in a block group.
+.TP
+.BI \-G " number-of-groups"
+Specify the number of block groups that will be packed together to
+create a larger virtual block group (or "flex_bg group") in an
+ext4 filesystem. This improves meta-data locality and performance
+on meta-data heavy workloads. The number of groups must be a power
+of 2 and may only be specified if the
+.B flex_bg
+filesystem feature is enabled.
+.TP
+.BI \-i " bytes-per-inode"
+Specify the bytes/inode ratio.
+.B mke2fs
+creates an inode for every
+.I bytes-per-inode
+bytes of space on the disk. The larger the
+.I bytes-per-inode
+ratio, the fewer inodes will be created. This value generally shouldn't
+be smaller than the blocksize of the filesystem, since in that case more
+inodes would be made than can ever be used. Be warned that it is not
+possible to change this ratio on a filesystem after it is created, so be
+careful deciding the correct value for this parameter. Note that resizing
+a filesystem changes the numer of inodes to maintain this ratio.
+.TP
+.BI \-I " inode-size"
+Specify the size of each inode in bytes.
+The
+.I inode-size
+value must be a power of 2 larger or equal to 128. The larger the
+.I inode-size
+the more space the inode table will consume, and this reduces the usable
+space in the filesystem and can also negatively impact performance.
+It is not
+possible to change this value after the filesystem is created.
+.IP
+In kernels after 2.6.10 and some
+earlier vendor kernels it is possible to utilize inodes larger than
+128 bytes to store
+extended attributes for improved performance.
+Extended attributes
+stored in large inodes are not visible with older kernels, and such
+filesystems will not be mountable with 2.4 kernels at all.
+.IP
+The default inode size is controlled by the
+.BR mke2fs.conf (5)
+file. In the
+.B mke2fs.conf
+file shipped with e2fsprogs, the default inode size is 256 bytes for
+most file systems, except for small file systems where the inode size
+will be 128 bytes.
+.TP
+.B \-j
+Create the filesystem with an ext3 journal. If the
+.B \-J
+option is not specified, the default journal parameters will be used to
+create an appropriately sized journal (given the size of the filesystem)
+stored within the filesystem. Note that you must be using a kernel
+which has ext3 support in order to actually make use of the journal.
+.TP
+.BI \-J " journal-options"
+Create the ext3 journal using options specified on the command-line.
+Journal options are comma
+separated, and may take an argument using the equals ('=') sign.
+The following journal options are supported:
+.RS 1.2i
+.TP
+.BI size= journal-size
+Create an internal journal (i.e., stored inside the filesystem) of size
+.I journal-size
+megabytes.
+The size of the journal must be at least 1024 filesystem blocks
+(i.e., 1MB if using 1k blocks, 4MB if using 4k blocks, etc.)
+and may be no more than 10,240,000 filesystem blocks or half the total
+file system size (whichever is smaller)
+@JDEV@.TP
+@JDEV@.BI device= external-journal
+@JDEV@Attach the filesystem to the journal block device located on
+@JDEV@.IR external-journal .
+@JDEV@The external
+@JDEV@journal must already have been created using the command
+@JDEV@.IP
+@JDEV@.B mke2fs -O journal_dev
+@JDEV@.I external-journal
+@JDEV@.IP
+@JDEV@Note that
+@JDEV@.I external-journal
+@JDEV@must have been created with the
+@JDEV@same block size as the new filesystem.
+@JDEV@In addition, while there is support for attaching
+@JDEV@multiple filesystems to a single external journal,
+@JDEV@the Linux kernel and
+@JDEV@.BR e2fsck (8)
+@JDEV@do not currently support shared external journals yet.
+@JDEV@.IP
+@JDEV@Instead of specifying a device name directly,
+@JDEV@.I external-journal
+@JDEV@can also be specified by either
+@JDEV@.BI LABEL= label
+@JDEV@or
+@JDEV@.BI UUID= UUID
+@JDEV@to locate the external journal by either the volume label or UUID
+@JDEV@stored in the ext2 superblock at the start of the journal. Use
+@JDEV@.BR dumpe2fs (8)
+@JDEV@to display a journal device's volume label and UUID. See also the
+@JDEV@.B -L
+@JDEV@option of
+@JDEV@.BR tune2fs (8).
+.RE
+@JDEV@.IP
+@JDEV@Only one of the
+@JDEV@.BR size " or " device
+@JDEV@options can be given for a filesystem.
+.TP
+.BI \-l " filename"
+Read the bad blocks list from
+.IR filename .
+Note that the block numbers in the bad block list must be generated
+using the same block size as used by
+.BR mke2fs .
+As a result, the
+.B \-c
+option to
+.B mke2fs
+is a much simpler and less error-prone method of checking a disk for bad
+blocks before formatting it, as
+.B mke2fs
+will automatically pass the correct parameters to the
+.B badblocks
+program.
+.TP
+.BI \-L " new-volume-label"
+Set the volume label for the filesystem to
+.IR new-volume-label .
+The maximum length of the
+volume label is 16 bytes.
+.TP
+.BI \-m " reserved-blocks-percentage"
+Specify the percentage of the filesystem blocks reserved for
+the super-user. This avoids fragmentation, and allows root-owned
+daemons, such as
+.BR syslogd (8),
+to continue to function correctly after non-privileged processes are
+prevented from writing to the filesystem. The default percentage
+is 5%.
+.TP
+.BI \-M " last-mounted-directory"
+Set the last mounted directory for the filesystem. This might be useful
+for the sake of utilities that key off of the last mounted directory to
+determine where the filesystem should be mounted.
+.TP
+.B \-n
+Causes
+.B mke2fs
+to not actually create a filesystem, but display what it
+would do if it were to create a filesystem. This can be used to
+determine the location of the backup superblocks for a particular
+filesystem, so long as the
+.B mke2fs
+parameters that were passed when the
+filesystem was originally created are used again. (With the
+.B \-n
+option added, of course!)
+.TP
+.BI \-N " number-of-inodes"
+Overrides the default calculation of the number of inodes that should be
+reserved for the filesystem (which is based on the number of blocks and
+the
+.I bytes-per-inode
+ratio). This allows the user to specify the number
+of desired inodes directly.
+.TP
+.BI \-o " creator-os"
+Overrides the default value of the "creator operating system" field of the
+filesystem. The creator field is set by default to the name of the OS the
+.B mke2fs
+executable was compiled for.
+.TP
+.B "\-O \fIfeature\fR[,...]"
+Create a filesystem with the given features (filesystem options),
+overriding the default filesystem options. The features that are
+enabled by default are specified by the
+.I base_features
+relation, either in the
+.I [defaults]
+section in the
+.B /etc/mke2fs.conf
+configuration file,
+or in the
+.I [fs_types]
+subsections for the usage types as specified by the
+.B \-T
+option, further modified by the
+.I features
+relation found in the
+.I [fs_types]
+subsections for the filesystem and usage types. See the
+.BR mke2fs.conf (5)
+manual page for more details.
+The filesystem type-specific configuration setting found in the
+.I [fs_types]
+section will override the global default found in
+.IR [defaults] .
+.sp
+The filesystem feature set will be further edited
+using either the feature set specified by this option,
+or if this option is not given, by the
+.I default_features
+relation for the filesystem type being created, or in the
+.I [defaults]
+section of the configuration file.
+.sp
+The filesystem feature set is comprised of a list of features, separated
+by commas, that are to be enabled. To disable a feature, simply
+prefix the feature name with a caret ('^') or a minus ('-') character.
+Features with dependencies will not be removed successfully.
+The pseudo-filesystem feature "none" will clear all filesystem features.
+.TP
+For more information about the features which can be set, please see
+the manual page
+.BR ext4 (5).
+.TP
+.B \-q
+Quiet execution. Useful if
+.B mke2fs
+is run in a script.
+.TP
+.BI \-r " revision"
+Set the filesystem revision for the new filesystem. Note that 1.2
+kernels only support revision 0 filesystems. The default is to
+create revision 1 filesystems.
+.TP
+.B \-S
+Write superblock and group descriptors only. This is useful if all of
+the superblock and backup superblocks are corrupted, and a last-ditch
+recovery method is desired. It causes
+.B mke2fs
+to reinitialize the
+superblock and group descriptors, while not touching the inode table
+and the block and inode bitmaps. The
+.B e2fsck
+program should be run immediately after this option is used, and there
+is no guarantee that any data will be salvageable. It is critical to
+specify the correct filesystem blocksize when using this option,
+or there is no chance of recovery.
+.\" .TP
+.\" .BI \-t " test"
+.\" Check the device for bad blocks before creating the file system
+.\" using the specified test.
+.TP
+.BI \-t " fs-type"
+Specify the filesystem type (i.e., ext2, ext3, ext4, etc.) that is
+to be created.
+If this option is not specified,
+.B mke2fs
+will pick a default either via how
+the command was run (for example, using a name of the form mkfs.ext2,
+mkfs.ext3, etc.) or via a default as defined by the
+.B /etc/mke2fs.conf
+file. This option controls which filesystem options are used by
+default, based on the
+.B fstypes
+configuration stanza in
+.BR /etc/mke2fs.conf .
+.sp
+If the
+.B \-O
+option is used to explicitly add or remove filesystem options that
+should be set in the newly created filesystem, the
+resulting filesystem may not be supported by the requested
+.IR fs-type .
+(e.g., "\fBmke2fs \-t ext3 \-O extent /dev/sdXX\fR" will create a
+filesystem that is not supported by the ext3 implementation as found in
+the Linux kernel; and "\fBmke2fs \-t ext3 \-O ^has_journal /dev/hdXX\fR"
+will create a filesystem that does not have a journal and hence will not
+be supported by the ext3 filesystem code in the Linux kernel.)
+.TP
+.BI \-T " usage-type[,...]"
+Specify how the filesystem is going to be used, so that
+.B mke2fs
+can choose optimal filesystem parameters for that use. The usage
+types that are supported are defined in the configuration file
+.BR /etc/mke2fs.conf .
+The user may specify one or more usage types
+using a comma separated list.
+.sp
+If this option is is not specified,
+.B mke2fs
+will pick a single default usage type based on the size of the filesystem to
+be created. If the filesystem size is less than or equal to 3 megabytes,
+.B mke2fs
+will use the filesystem type
+.IR floppy .
+If the filesystem size is greater than 3 but less than or equal to
+512 megabytes,
+.BR mke2fs (8)
+will use the filesystem type
+.IR small .
+If the filesystem size is greater than or equal to 4 terabytes but less than
+16 terabytes,
+.BR mke2fs (8)
+will use the filesystem type
+.IR big .
+If the filesystem size is greater than or equal to 16 terabytes,
+.BR mke2fs (8)
+will use the filesystem type
+.IR huge .
+Otherwise,
+.BR mke2fs (8)
+will use the default filesystem type
+.IR default .
+.TP
+.BI \-U " UUID"
+Create the filesystem with the specified UUID.
+.TP
+.B \-v
+Verbose execution.
+.TP
+.B \-V
+Print the version number of
+.B mke2fs
+and exit.
+.SH ENVIRONMENT
+.TP
+.BI MKE2FS_SYNC
+If set to non-zero integer value, its value is used to determine how often
+.BR sync (2)
+is called during inode table initialization.
+.TP
+.BI MKE2FS_CONFIG
+Determines the location of the configuration file (see
+.BR mke2fs.conf (5)).
+.TP
+.BI MKE2FS_FIRST_META_BG
+If set to non-zero integer value, its value is used to determine first meta
+block group. This is mostly for debugging purposes.
+.TP
+.BI MKE2FS_DEVICE_SECTSIZE
+If set to non-zero integer value, its value is used to determine physical
+sector size of the
+.IR device .
+.TP
+.BI MKE2FS_SKIP_CHECK_MSG
+If set, do not show the message of filesystem automatic check caused by
+mount count or check interval.
+.SH AUTHOR
+This version of
+.B mke2fs
+has been written by Theodore Ts'o <tytso@mit.edu>.
+.SH BUGS
+.B mke2fs
+accepts the
+.B \-f
+option but currently ignores it because the second
+extended file system does not support fragments yet.
+.br
+There may be other ones. Please, report them to the author.
+.SH AVAILABILITY
+.B mke2fs
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR mke2fs.conf (5),
+.BR badblocks (8),
+.BR dumpe2fs (8),
+.BR e2fsck (8),
+.BR tune2fs (8),
+.BR ext4 (5)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.c
new file mode 100644
index 0000000..2e8ba60
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.c
@@ -0,0 +1,2751 @@
+/*
+ * mke2fs.c - Make a ext2fs filesystem.
+ *
+ * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ * 2003, 2004, 2005 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/* Usage: mke2fs [options] device
+ *
+ * The device may be a block device or a image of one, but this isn't
+ * enforced (but it's not much fun on a character device :-).
+ */
+
+#define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX in Solaris */
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <time.h>
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libgen.h>
+#include <limits.h>
+#include <blkid/blkid.h>
+
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fsP.h"
+#include "et/com_err.h"
+#include "uuid/uuid.h"
+#include "e2p/e2p.h"
+#include "ext2fs/ext2fs.h"
+#include "util.h"
+#include "profile.h"
+#include "prof_err.h"
+#include "../version.h"
+#include "nls-enable.h"
+#include "quota/mkquota.h"
+
+#define STRIDE_LENGTH 8
+
+#define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1)
+
+#ifndef __sparc__
+#define ZAP_BOOTBLOCK
+#endif
+
+#define DISCARD_STEP_MB (2048)
+
+extern int isatty(int);
+extern FILE *fpopen(const char *cmd, const char *mode);
+
+static const char * program_name = "mke2fs";
+static const char * device_name /* = NULL */;
+
+/* Command line options */
+static int cflag;
+static int verbose;
+static int quiet;
+static int super_only;
+static int discard = 1; /* attempt to discard device before fs creation */
+static int direct_io;
+static int force;
+static int noaction;
+static uid_t root_uid;
+static gid_t root_gid;
+int journal_size;
+int journal_flags;
+static int lazy_itable_init;
+static char *bad_blocks_filename = NULL;
+static __u32 fs_stride;
+static int quotatype = -1; /* Initialize both user and group quotas by default */
+
+static struct ext2_super_block fs_param;
+static char *fs_uuid = NULL;
+static char *creator_os;
+static char *volume_label;
+static char *mount_dir;
+char *journal_device;
+static int sync_kludge; /* Set using the MKE2FS_SYNC env. option */
+static char **fs_types;
+
+static profile_t profile;
+
+static int sys_page_size = 4096;
+static int linux_version_code = 0;
+
+static void usage(void)
+{
+ fprintf(stderr, _("Usage: %s [-c|-l filename] [-b block-size] "
+ "[-C cluster-size]\n\t[-i bytes-per-inode] [-I inode-size] "
+ "[-J journal-options]\n"
+ "\t[-G flex-group-size] [-N number-of-inodes]\n"
+ "\t[-m reserved-blocks-percentage] [-o creator-os]\n"
+ "\t[-g blocks-per-group] [-L volume-label] "
+ "[-M last-mounted-directory]\n\t[-O feature[,...]] "
+ "[-r fs-revision] [-E extended-option[,...]]\n"
+ "\t[-t fs-type] [-T usage-type ] [-U UUID] "
+ "[-jnqvDFKSV] device [blocks-count]\n"),
+ program_name);
+ exit(1);
+}
+
+static int int_log2(unsigned long long arg)
+{
+ int l = 0;
+
+ arg >>= 1;
+ while (arg) {
+ l++;
+ arg >>= 1;
+ }
+ return l;
+}
+
+static int int_log10(unsigned long long arg)
+{
+ int l;
+
+ for (l=0; arg ; l++)
+ arg = arg / 10;
+ return l;
+}
+
+#ifdef __linux__
+static int parse_version_number(const char *s)
+{
+ int major, minor, rev;
+ char *endptr;
+ const char *cp = s;
+
+ if (!s)
+ return 0;
+ major = strtol(cp, &endptr, 10);
+ if (cp == endptr || *endptr != '.')
+ return 0;
+ cp = endptr + 1;
+ minor = strtol(cp, &endptr, 10);
+ if (cp == endptr || *endptr != '.')
+ return 0;
+ cp = endptr + 1;
+ rev = strtol(cp, &endptr, 10);
+ if (cp == endptr)
+ return 0;
+ return ((((major * 256) + minor) * 256) + rev);
+}
+#endif
+
+/*
+ * Helper function for read_bb_file and test_disk
+ */
+static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk)
+{
+ fprintf(stderr, _("Bad block %u out of range; ignored.\n"), blk);
+ return;
+}
+
+/*
+ * Reads the bad blocks list from a file
+ */
+static void read_bb_file(ext2_filsys fs, badblocks_list *bb_list,
+ const char *bad_blocks_file)
+{
+ FILE *f;
+ errcode_t retval;
+
+ f = fopen(bad_blocks_file, "r");
+ if (!f) {
+ com_err("read_bad_blocks_file", errno,
+ _("while trying to open %s"), bad_blocks_file);
+ exit(1);
+ }
+ retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
+ fclose (f);
+ if (retval) {
+ com_err("ext2fs_read_bb_FILE", retval, "%s",
+ _("while reading in list of bad blocks from file"));
+ exit(1);
+ }
+}
+
+/*
+ * Runs the badblocks program to test the disk
+ */
+static void test_disk(ext2_filsys fs, badblocks_list *bb_list)
+{
+ FILE *f;
+ errcode_t retval;
+ char buf[1024];
+
+ sprintf(buf, "badblocks -b %d -X %s%s%s %llu", fs->blocksize,
+ quiet ? "" : "-s ", (cflag > 1) ? "-w " : "",
+ fs->device_name, ext2fs_blocks_count(fs->super)-1);
+ if (verbose)
+ printf(_("Running command: %s\n"), buf);
+ f = popen(buf, "r");
+ if (!f) {
+ com_err("popen", errno,
+ _("while trying to run '%s'"), buf);
+ exit(1);
+ }
+ retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
+ pclose(f);
+ if (retval) {
+ com_err("ext2fs_read_bb_FILE", retval, "%s",
+ _("while processing list of bad blocks from program"));
+ exit(1);
+ }
+}
+
+static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list)
+{
+ dgrp_t i;
+ blk_t j;
+ unsigned must_be_good;
+ blk_t blk;
+ badblocks_iterate bb_iter;
+ errcode_t retval;
+ blk_t group_block;
+ int group;
+ int group_bad;
+
+ if (!bb_list)
+ return;
+
+ /*
+ * The primary superblock and group descriptors *must* be
+ * good; if not, abort.
+ */
+ must_be_good = fs->super->s_first_data_block + 1 + fs->desc_blocks;
+ for (i = fs->super->s_first_data_block; i <= must_be_good; i++) {
+ if (ext2fs_badblocks_list_test(bb_list, i)) {
+ fprintf(stderr, _("Block %d in primary "
+ "superblock/group descriptor area bad.\n"), i);
+ fprintf(stderr, _("Blocks %u through %u must be good "
+ "in order to build a filesystem.\n"),
+ fs->super->s_first_data_block, must_be_good);
+ fputs(_("Aborting....\n"), stderr);
+ exit(1);
+ }
+ }
+
+ /*
+ * See if any of the bad blocks are showing up in the backup
+ * superblocks and/or group descriptors. If so, issue a
+ * warning and adjust the block counts appropriately.
+ */
+ group_block = fs->super->s_first_data_block +
+ fs->super->s_blocks_per_group;
+
+ for (i = 1; i < fs->group_desc_count; i++) {
+ group_bad = 0;
+ for (j=0; j < fs->desc_blocks+1; j++) {
+ if (ext2fs_badblocks_list_test(bb_list,
+ group_block + j)) {
+ if (!group_bad)
+ fprintf(stderr,
+_("Warning: the backup superblock/group descriptors at block %u contain\n"
+" bad blocks.\n\n"),
+ group_block);
+ group_bad++;
+ group = ext2fs_group_of_blk2(fs, group_block+j);
+ ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) + 1);
+ ext2fs_group_desc_csum_set(fs, group);
+ ext2fs_free_blocks_count_add(fs->super, 1);
+ }
+ }
+ group_block += fs->super->s_blocks_per_group;
+ }
+
+ /*
+ * Mark all the bad blocks as used...
+ */
+ retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
+ if (retval) {
+ com_err("ext2fs_badblocks_list_iterate_begin", retval, "%s",
+ _("while marking bad blocks as used"));
+ exit(1);
+ }
+ while (ext2fs_badblocks_list_iterate(bb_iter, &blk))
+ ext2fs_mark_block_bitmap2(fs->block_map, EXT2FS_B2C(fs, blk));
+ ext2fs_badblocks_list_iterate_end(bb_iter);
+}
+
+static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
+{
+ errcode_t retval;
+ blk64_t blk;
+ dgrp_t i;
+ int num;
+ struct ext2fs_numeric_progress_struct progress;
+
+ ext2fs_numeric_progress_init(fs, &progress,
+ _("Writing inode tables: "),
+ fs->group_desc_count);
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ ext2fs_numeric_progress_update(fs, &progress, i);
+
+ blk = ext2fs_inode_table_loc(fs, i);
+ num = fs->inode_blocks_per_group;
+
+ if (lazy_flag)
+ num = ext2fs_div_ceil((fs->super->s_inodes_per_group -
+ ext2fs_bg_itable_unused(fs, i)) *
+ EXT2_INODE_SIZE(fs->super),
+ EXT2_BLOCK_SIZE(fs->super));
+ if (!lazy_flag || itable_zeroed) {
+ /* The kernel doesn't need to zero the itable blocks */
+ ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_ZEROED);
+ ext2fs_group_desc_csum_set(fs, i);
+ }
+ retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num);
+ if (retval) {
+ fprintf(stderr, _("\nCould not write %d "
+ "blocks in inode table starting at %llu: %s\n"),
+ num, blk, error_message(retval));
+ exit(1);
+ }
+ if (sync_kludge) {
+ if (sync_kludge == 1)
+ sync();
+ else if ((i % sync_kludge) == 0)
+ sync();
+ }
+ }
+ ext2fs_zero_blocks2(0, 0, 0, 0, 0);
+ ext2fs_numeric_progress_close(fs, &progress,
+ _("done \n"));
+}
+
+static void create_root_dir(ext2_filsys fs)
+{
+ errcode_t retval;
+ struct ext2_inode inode;
+
+ retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
+ if (retval) {
+ com_err("ext2fs_mkdir", retval, "%s",
+ _("while creating root dir"));
+ exit(1);
+ }
+ if (root_uid != 0 || root_gid != 0) {
+ retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode);
+ if (retval) {
+ com_err("ext2fs_read_inode", retval, "%s",
+ _("while reading root inode"));
+ exit(1);
+ }
+
+ inode.i_uid = root_uid;
+ ext2fs_set_i_uid_high(inode, root_uid >> 16);
+ inode.i_gid = root_gid;
+ ext2fs_set_i_gid_high(inode, root_gid >> 16);
+
+ retval = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
+ if (retval) {
+ com_err("ext2fs_write_inode", retval, "%s",
+ _("while setting root inode ownership"));
+ exit(1);
+ }
+ }
+}
+
+static void create_lost_and_found(ext2_filsys fs)
+{
+ unsigned int lpf_size = 0;
+ errcode_t retval;
+ ext2_ino_t ino;
+ const char *name = "lost+found";
+ int i;
+
+ fs->umask = 077;
+ retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name);
+ if (retval) {
+ com_err("ext2fs_mkdir", retval, "%s",
+ _("while creating /lost+found"));
+ exit(1);
+ }
+
+ retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino);
+ if (retval) {
+ com_err("ext2_lookup", retval, "%s",
+ _("while looking up /lost+found"));
+ exit(1);
+ }
+
+ for (i=1; i < EXT2_NDIR_BLOCKS; i++) {
+ /* Ensure that lost+found is at least 2 blocks, so we always
+ * test large empty blocks for big-block filesystems. */
+ if ((lpf_size += fs->blocksize) >= 16*1024 &&
+ lpf_size >= 2 * fs->blocksize)
+ break;
+ retval = ext2fs_expand_dir(fs, ino);
+ if (retval) {
+ com_err("ext2fs_expand_dir", retval, "%s",
+ _("while expanding /lost+found"));
+ exit(1);
+ }
+ }
+}
+
+static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list)
+{
+ errcode_t retval;
+
+ ext2fs_mark_inode_bitmap2(fs->inode_map, EXT2_BAD_INO);
+ ext2fs_inode_alloc_stats2(fs, EXT2_BAD_INO, +1, 0);
+ retval = ext2fs_update_bb_inode(fs, bb_list);
+ if (retval) {
+ com_err("ext2fs_update_bb_inode", retval, "%s",
+ _("while setting bad block inode"));
+ exit(1);
+ }
+
+}
+
+static void reserve_inodes(ext2_filsys fs)
+{
+ ext2_ino_t i;
+
+ for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++)
+ ext2fs_inode_alloc_stats2(fs, i, +1, 0);
+ ext2fs_mark_ib_dirty(fs);
+}
+
+#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
+#define BSD_MAGICDISK (0x57455682UL) /* The disk magic number reversed */
+#define BSD_LABEL_OFFSET 64
+
+static void zap_sector(ext2_filsys fs, int sect, int nsect)
+{
+ char *buf;
+ int retval;
+ unsigned int *magic;
+
+ buf = malloc(512*nsect);
+ if (!buf) {
+ printf(_("Out of memory erasing sectors %d-%d\n"),
+ sect, sect + nsect - 1);
+ exit(1);
+ }
+
+ if (sect == 0) {
+ /* Check for a BSD disklabel, and don't erase it if so */
+ retval = io_channel_read_blk64(fs->io, 0, -512, buf);
+ if (retval)
+ fprintf(stderr,
+ _("Warning: could not read block 0: %s\n"),
+ error_message(retval));
+ else {
+ magic = (unsigned int *) (buf + BSD_LABEL_OFFSET);
+ if ((*magic == BSD_DISKMAGIC) ||
+ (*magic == BSD_MAGICDISK))
+ return;
+ }
+ }
+
+ memset(buf, 0, 512*nsect);
+ io_channel_set_blksize(fs->io, 512);
+ retval = io_channel_write_blk64(fs->io, sect, -512*nsect, buf);
+ io_channel_set_blksize(fs->io, fs->blocksize);
+ free(buf);
+ if (retval)
+ fprintf(stderr, _("Warning: could not erase sector %d: %s\n"),
+ sect, error_message(retval));
+}
+
+static void create_journal_dev(ext2_filsys fs)
+{
+ struct ext2fs_numeric_progress_struct progress;
+ errcode_t retval;
+ char *buf;
+ blk64_t blk, err_blk;
+ int c, count, err_count;
+
+ retval = ext2fs_create_journal_superblock(fs,
+ ext2fs_blocks_count(fs->super), 0, &buf);
+ if (retval) {
+ com_err("create_journal_dev", retval, "%s",
+ _("while initializing journal superblock"));
+ exit(1);
+ }
+
+ if (journal_flags & EXT2_MKJOURNAL_LAZYINIT)
+ goto write_superblock;
+
+ ext2fs_numeric_progress_init(fs, &progress,
+ _("Zeroing journal device: "),
+ ext2fs_blocks_count(fs->super));
+ blk = 0;
+ count = ext2fs_blocks_count(fs->super);
+ while (count > 0) {
+ if (count > 1024)
+ c = 1024;
+ else
+ c = count;
+ retval = ext2fs_zero_blocks2(fs, blk, c, &err_blk, &err_count);
+ if (retval) {
+ com_err("create_journal_dev", retval,
+ _("while zeroing journal device "
+ "(block %llu, count %d)"),
+ err_blk, err_count);
+ exit(1);
+ }
+ blk += c;
+ count -= c;
+ ext2fs_numeric_progress_update(fs, &progress, blk);
+ }
+ ext2fs_zero_blocks2(0, 0, 0, 0, 0);
+
+ ext2fs_numeric_progress_close(fs, &progress, NULL);
+write_superblock:
+ retval = io_channel_write_blk64(fs->io,
+ fs->super->s_first_data_block+1,
+ 1, buf);
+ if (retval) {
+ com_err("create_journal_dev", retval, "%s",
+ _("while writing journal superblock"));
+ exit(1);
+ }
+}
+
+static void show_stats(ext2_filsys fs)
+{
+ struct ext2_super_block *s = fs->super;
+ char buf[80];
+ char *os;
+ blk64_t group_block;
+ dgrp_t i;
+ int need, col_left;
+
+ if (ext2fs_blocks_count(&fs_param) != ext2fs_blocks_count(s))
+ fprintf(stderr, _("warning: %llu blocks unused.\n\n"),
+ ext2fs_blocks_count(&fs_param) - ext2fs_blocks_count(s));
+
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, s->s_volume_name, sizeof(s->s_volume_name));
+ printf(_("Filesystem label=%s\n"), buf);
+ os = e2p_os2string(fs->super->s_creator_os);
+ if (os)
+ printf(_("OS type: %s\n"), os);
+ free(os);
+ printf(_("Block size=%u (log=%u)\n"), fs->blocksize,
+ s->s_log_block_size);
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+ printf(_("Cluster size=%u (log=%u)\n"),
+ fs->blocksize << fs->cluster_ratio_bits,
+ s->s_log_cluster_size);
+ else
+ printf(_("Fragment size=%u (log=%u)\n"), EXT2_CLUSTER_SIZE(s),
+ s->s_log_cluster_size);
+ printf(_("Stride=%u blocks, Stripe width=%u blocks\n"),
+ s->s_raid_stride, s->s_raid_stripe_width);
+ printf(_("%u inodes, %llu blocks\n"), s->s_inodes_count,
+ ext2fs_blocks_count(s));
+ printf(_("%llu blocks (%2.2f%%) reserved for the super user\n"),
+ ext2fs_r_blocks_count(s),
+ 100.0 * ext2fs_r_blocks_count(s) / ext2fs_blocks_count(s));
+ printf(_("First data block=%u\n"), s->s_first_data_block);
+ if (root_uid != 0 || root_gid != 0)
+ printf(_("Root directory owner=%u:%u\n"), root_uid, root_gid);
+ if (s->s_reserved_gdt_blocks)
+ printf(_("Maximum filesystem blocks=%lu\n"),
+ (s->s_reserved_gdt_blocks + fs->desc_blocks) *
+ EXT2_DESC_PER_BLOCK(s) * s->s_blocks_per_group);
+ if (fs->group_desc_count > 1)
+ printf(_("%u block groups\n"), fs->group_desc_count);
+ else
+ printf(_("%u block group\n"), fs->group_desc_count);
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+ printf(_("%u blocks per group, %u clusters per group\n"),
+ s->s_blocks_per_group, s->s_clusters_per_group);
+ else
+ printf(_("%u blocks per group, %u fragments per group\n"),
+ s->s_blocks_per_group, s->s_clusters_per_group);
+ printf(_("%u inodes per group\n"), s->s_inodes_per_group);
+
+ if (fs->group_desc_count == 1) {
+ printf("\n");
+ return;
+ }
+
+ printf("%s", _("Superblock backups stored on blocks: "));
+ group_block = s->s_first_data_block;
+ col_left = 0;
+ for (i = 1; i < fs->group_desc_count; i++) {
+ group_block += s->s_blocks_per_group;
+ if (!ext2fs_bg_has_super(fs, i))
+ continue;
+ if (i != 1)
+ printf(", ");
+ need = int_log10(group_block) + 2;
+ if (need > col_left) {
+ printf("\n\t");
+ col_left = 72;
+ }
+ col_left -= need;
+ printf("%llu", group_block);
+ }
+ printf("\n\n");
+}
+
+/*
+ * Set the S_CREATOR_OS field. Return true if OS is known,
+ * otherwise, 0.
+ */
+static int set_os(struct ext2_super_block *sb, char *os)
+{
+ if (isdigit (*os))
+ sb->s_creator_os = atoi (os);
+ else if (strcasecmp(os, "linux") == 0)
+ sb->s_creator_os = EXT2_OS_LINUX;
+ else if (strcasecmp(os, "GNU") == 0 || strcasecmp(os, "hurd") == 0)
+ sb->s_creator_os = EXT2_OS_HURD;
+ else if (strcasecmp(os, "freebsd") == 0)
+ sb->s_creator_os = EXT2_OS_FREEBSD;
+ else if (strcasecmp(os, "lites") == 0)
+ sb->s_creator_os = EXT2_OS_LITES;
+ else
+ return 0;
+ return 1;
+}
+
+#define PATH_SET "PATH=/sbin"
+
+static void parse_extended_opts(struct ext2_super_block *param,
+ const char *opts)
+{
+ char *buf, *token, *next, *p, *arg, *badopt = 0;
+ int len;
+ int r_usage = 0;
+
+ len = strlen(opts);
+ buf = malloc(len+1);
+ if (!buf) {
+ fprintf(stderr, "%s",
+ _("Couldn't allocate memory to parse options!\n"));
+ exit(1);
+ }
+ strcpy(buf, opts);
+ for (token = buf; token && *token; token = next) {
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+ arg = strchr(token, '=');
+ if (arg) {
+ *arg = 0;
+ arg++;
+ }
+ if (strcmp(token, "desc-size") == 0 ||
+ strcmp(token, "desc_size") == 0) {
+ int desc_size;
+
+ if (!(fs_param.s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_64BIT)) {
+ fprintf(stderr,
+ _("%s requires '-O 64bit'\n"), token);
+ r_usage++;
+ continue;
+ }
+ if (param->s_reserved_gdt_blocks != 0) {
+ fprintf(stderr,
+ _("'%s' must be before 'resize=%u'\n"),
+ token, param->s_reserved_gdt_blocks);
+ r_usage++;
+ continue;
+ }
+ if (!arg) {
+ r_usage++;
+ badopt = token;
+ continue;
+ }
+ desc_size = strtoul(arg, &p, 0);
+ if (*p || (desc_size & (desc_size - 1))) {
+ fprintf(stderr,
+ _("Invalid desc_size: '%s'\n"), arg);
+ r_usage++;
+ continue;
+ }
+ param->s_desc_size = desc_size;
+ } else if (strcmp(token, "mmp_update_interval") == 0) {
+ if (!arg) {
+ r_usage++;
+ badopt = token;
+ continue;
+ }
+ param->s_mmp_update_interval = strtoul(arg, &p, 0);
+ if (*p) {
+ fprintf(stderr,
+ _("Invalid mmp_update_interval: %s\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ } else if (strcmp(token, "stride") == 0) {
+ if (!arg) {
+ r_usage++;
+ badopt = token;
+ continue;
+ }
+ param->s_raid_stride = strtoul(arg, &p, 0);
+ if (*p) {
+ fprintf(stderr,
+ _("Invalid stride parameter: %s\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ } else if (strcmp(token, "stripe-width") == 0 ||
+ strcmp(token, "stripe_width") == 0) {
+ if (!arg) {
+ r_usage++;
+ badopt = token;
+ continue;
+ }
+ param->s_raid_stripe_width = strtoul(arg, &p, 0);
+ if (*p) {
+ fprintf(stderr,
+ _("Invalid stripe-width parameter: %s\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ } else if (!strcmp(token, "resize")) {
+ blk64_t resize;
+ unsigned long bpg, rsv_groups;
+ unsigned long group_desc_count, desc_blocks;
+ unsigned int gdpb, blocksize;
+ int rsv_gdb;
+
+ if (!arg) {
+ r_usage++;
+ badopt = token;
+ continue;
+ }
+
+ resize = parse_num_blocks2(arg,
+ param->s_log_block_size);
+
+ if (resize == 0) {
+ fprintf(stderr,
+ _("Invalid resize parameter: %s\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ if (resize <= ext2fs_blocks_count(param)) {
+ fprintf(stderr, "%s",
+ _("The resize maximum must be greater "
+ "than the filesystem size.\n"));
+ r_usage++;
+ continue;
+ }
+
+ blocksize = EXT2_BLOCK_SIZE(param);
+ bpg = param->s_blocks_per_group;
+ if (!bpg)
+ bpg = blocksize * 8;
+ gdpb = EXT2_DESC_PER_BLOCK(param);
+ group_desc_count = (__u32) ext2fs_div64_ceil(
+ ext2fs_blocks_count(param), bpg);
+ desc_blocks = (group_desc_count +
+ gdpb - 1) / gdpb;
+ rsv_groups = ext2fs_div64_ceil(resize, bpg);
+ rsv_gdb = ext2fs_div_ceil(rsv_groups, gdpb) -
+ desc_blocks;
+ if (rsv_gdb > (int) EXT2_ADDR_PER_BLOCK(param))
+ rsv_gdb = EXT2_ADDR_PER_BLOCK(param);
+
+ if (rsv_gdb > 0) {
+ if (param->s_rev_level == EXT2_GOOD_OLD_REV) {
+ fprintf(stderr, "%s",
+ _("On-line resizing not supported with revision 0 filesystems\n"));
+ free(buf);
+ exit(1);
+ }
+ param->s_feature_compat |=
+ EXT2_FEATURE_COMPAT_RESIZE_INODE;
+
+ param->s_reserved_gdt_blocks = rsv_gdb;
+ }
+ } else if (!strcmp(token, "test_fs")) {
+ param->s_flags |= EXT2_FLAGS_TEST_FILESYS;
+ } else if (!strcmp(token, "lazy_itable_init")) {
+ if (arg)
+ lazy_itable_init = strtoul(arg, &p, 0);
+ else
+ lazy_itable_init = 1;
+ } else if (!strcmp(token, "lazy_journal_init")) {
+ if (arg)
+ journal_flags |= strtoul(arg, &p, 0) ?
+ EXT2_MKJOURNAL_LAZYINIT : 0;
+ else
+ journal_flags |= EXT2_MKJOURNAL_LAZYINIT;
+ } else if (!strcmp(token, "root_owner")) {
+ if (arg) {
+ root_uid = strtoul(arg, &p, 0);
+ if (*p != ':') {
+ fprintf(stderr,
+ _("Invalid root_owner: '%s'\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ p++;
+ root_gid = strtoul(p, &p, 0);
+ if (*p) {
+ fprintf(stderr,
+ _("Invalid root_owner: '%s'\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ } else {
+ root_uid = getuid();
+ root_gid = getgid();
+ }
+ } else if (!strcmp(token, "discard")) {
+ discard = 1;
+ } else if (!strcmp(token, "nodiscard")) {
+ discard = 0;
+ } else if (!strcmp(token, "quotatype")) {
+ if (!arg) {
+ r_usage++;
+ badopt = token;
+ continue;
+ }
+ if (!strncmp(arg, "usr", 3)) {
+ quotatype = 0;
+ } else if (!strncmp(arg, "grp", 3)) {
+ quotatype = 1;
+ } else {
+ fprintf(stderr,
+ _("Invalid quotatype parameter: %s\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ } else {
+ r_usage++;
+ badopt = token;
+ }
+ }
+ if (r_usage) {
+ fprintf(stderr, _("\nBad option(s) specified: %s\n\n"
+ "Extended options are separated by commas, "
+ "and may take an argument which\n"
+ "\tis set off by an equals ('=') sign.\n\n"
+ "Valid extended options are:\n"
+ "\tstride=<RAID per-disk data chunk in blocks>\n"
+ "\tstripe-width=<RAID stride * data disks in blocks>\n"
+ "\tresize=<resize maximum size in blocks>\n"
+ "\tlazy_itable_init=<0 to disable, 1 to enable>\n"
+ "\tlazy_journal_init=<0 to disable, 1 to enable>\n"
+ "\troot_uid=<uid of root directory>\n"
+ "\troot_gid=<gid of root directory>\n"
+ "\ttest_fs\n"
+ "\tdiscard\n"
+ "\tnodiscard\n"
+ "\tquotatype=<usr OR grp>\n\n"),
+ badopt ? badopt : "");
+ free(buf);
+ exit(1);
+ }
+ if (param->s_raid_stride &&
+ (param->s_raid_stripe_width % param->s_raid_stride) != 0)
+ fprintf(stderr, _("\nWarning: RAID stripe-width %u not an even "
+ "multiple of stride %u.\n\n"),
+ param->s_raid_stripe_width, param->s_raid_stride);
+
+ free(buf);
+}
+
+static __u32 ok_features[3] = {
+ /* Compat */
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL |
+ EXT2_FEATURE_COMPAT_RESIZE_INODE |
+ EXT2_FEATURE_COMPAT_DIR_INDEX |
+ EXT2_FEATURE_COMPAT_EXT_ATTR,
+ /* Incompat */
+ EXT2_FEATURE_INCOMPAT_FILETYPE|
+ EXT3_FEATURE_INCOMPAT_EXTENTS|
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
+ EXT2_FEATURE_INCOMPAT_META_BG|
+ EXT4_FEATURE_INCOMPAT_FLEX_BG|
+ EXT4_FEATURE_INCOMPAT_MMP |
+ EXT4_FEATURE_INCOMPAT_64BIT,
+ /* R/O compat */
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
+ EXT4_FEATURE_RO_COMPAT_BIGALLOC|
+#ifdef CONFIG_QUOTA
+ EXT4_FEATURE_RO_COMPAT_QUOTA|
+#endif
+ 0
+};
+
+
+static void syntax_err_report(const char *filename, long err, int line_num)
+{
+ fprintf(stderr,
+ _("Syntax error in mke2fs config file (%s, line #%d)\n\t%s\n"),
+ filename, line_num, error_message(err));
+ exit(1);
+}
+
+static const char *config_fn[] = { ROOT_SYSCONFDIR "/mke2fs.conf", 0 };
+
+static void edit_feature(const char *str, __u32 *compat_array)
+{
+ if (!str)
+ return;
+
+ if (e2p_edit_feature(str, compat_array, ok_features)) {
+ fprintf(stderr, _("Invalid filesystem option set: %s\n"),
+ str);
+ exit(1);
+ }
+}
+
+static void edit_mntopts(const char *str, __u32 *mntopts)
+{
+ if (!str)
+ return;
+
+ if (e2p_edit_mntopts(str, mntopts, ~0)) {
+ fprintf(stderr, _("Invalid mount option set: %s\n"),
+ str);
+ exit(1);
+ }
+}
+
+struct str_list {
+ char **list;
+ int num;
+ int max;
+};
+
+static errcode_t init_list(struct str_list *sl)
+{
+ sl->num = 0;
+ sl->max = 0;
+ sl->list = malloc((sl->max+1) * sizeof(char *));
+ if (!sl->list)
+ return ENOMEM;
+ sl->list[0] = 0;
+ return 0;
+}
+
+static errcode_t push_string(struct str_list *sl, const char *str)
+{
+ char **new_list;
+
+ if (sl->num >= sl->max) {
+ sl->max += 2;
+ new_list = realloc(sl->list, (sl->max+1) * sizeof(char *));
+ if (!new_list)
+ return ENOMEM;
+ sl->list = new_list;
+ }
+ sl->list[sl->num] = malloc(strlen(str)+1);
+ if (sl->list[sl->num] == 0)
+ return ENOMEM;
+ strcpy(sl->list[sl->num], str);
+ sl->num++;
+ sl->list[sl->num] = 0;
+ return 0;
+}
+
+static void print_str_list(char **list)
+{
+ char **cpp;
+
+ for (cpp = list; *cpp; cpp++) {
+ printf("'%s'", *cpp);
+ if (cpp[1])
+ fputs(", ", stdout);
+ }
+ fputc('\n', stdout);
+}
+
+/*
+ * Return TRUE if the profile has the given subsection
+ */
+static int profile_has_subsection(profile_t prof, const char *section,
+ const char *subsection)
+{
+ void *state;
+ const char *names[4];
+ char *name;
+ int ret = 0;
+
+ names[0] = section;
+ names[1] = subsection;
+ names[2] = 0;
+
+ if (profile_iterator_create(prof, names,
+ PROFILE_ITER_LIST_SECTION |
+ PROFILE_ITER_RELATIONS_ONLY, &state))
+ return 0;
+
+ if ((profile_iterator(&state, &name, 0) == 0) && name) {
+ free(name);
+ ret = 1;
+ }
+
+ profile_iterator_free(&state);
+ return ret;
+}
+
+static char **parse_fs_type(const char *fs_type,
+ const char *usage_types,
+ struct ext2_super_block *sb,
+ blk64_t fs_blocks_count,
+ char *progname)
+{
+ const char *ext_type = 0;
+ char *parse_str;
+ char *profile_type = 0;
+ char *cp, *t;
+ const char *size_type;
+ struct str_list list;
+ unsigned long long meg;
+ int is_hurd = 0;
+
+ if (init_list(&list))
+ return 0;
+
+ if (creator_os && (!strcasecmp(creator_os, "GNU") ||
+ !strcasecmp(creator_os, "hurd")))
+ is_hurd = 1;
+
+ if (fs_type)
+ ext_type = fs_type;
+ else if (is_hurd)
+ ext_type = "ext2";
+ else if (!strcmp(program_name, "mke3fs"))
+ ext_type = "ext3";
+ else if (!strcmp(program_name, "mke4fs"))
+ ext_type = "ext4";
+ else if (progname) {
+ ext_type = strrchr(progname, '/');
+ if (ext_type)
+ ext_type++;
+ else
+ ext_type = progname;
+
+ if (!strncmp(ext_type, "mkfs.", 5)) {
+ ext_type += 5;
+ if (ext_type[0] == 0)
+ ext_type = 0;
+ } else
+ ext_type = 0;
+ }
+
+ if (!ext_type) {
+ profile_get_string(profile, "defaults", "fs_type", 0,
+ "ext2", &profile_type);
+ ext_type = profile_type;
+ if (!strcmp(ext_type, "ext2") && (journal_size != 0))
+ ext_type = "ext3";
+ }
+
+
+ if (!profile_has_subsection(profile, "fs_types", ext_type) &&
+ strcmp(ext_type, "ext2")) {
+ printf(_("\nYour mke2fs.conf file does not define the "
+ "%s filesystem type.\n"), ext_type);
+ if (!strcmp(ext_type, "ext3") || !strcmp(ext_type, "ext4") ||
+ !strcmp(ext_type, "ext4dev")) {
+ printf("%s", _("You probably need to install an "
+ "updated mke2fs.conf file.\n\n"));
+ }
+ if (!force) {
+ printf("%s", _("Aborting...\n"));
+ exit(1);
+ }
+ }
+
+ meg = (1024 * 1024) / EXT2_BLOCK_SIZE(sb);
+ if (fs_blocks_count < 3 * meg)
+ size_type = "floppy";
+ else if (fs_blocks_count < 512 * meg)
+ size_type = "small";
+ else if (fs_blocks_count < 4 * 1024 * 1024 * meg)
+ size_type = "default";
+ else if (fs_blocks_count < 16 * 1024 * 1024 * meg)
+ size_type = "big";
+ else
+ size_type = "huge";
+
+ if (!usage_types)
+ usage_types = size_type;
+
+ parse_str = malloc(strlen(usage_types)+1);
+ if (!parse_str) {
+ free(profile_type);
+ free(list.list);
+ return 0;
+ }
+ strcpy(parse_str, usage_types);
+
+ if (ext_type)
+ push_string(&list, ext_type);
+ cp = parse_str;
+ while (1) {
+ t = strchr(cp, ',');
+ if (t)
+ *t = '\0';
+
+ if (*cp) {
+ if (profile_has_subsection(profile, "fs_types", cp))
+ push_string(&list, cp);
+ else if (strcmp(cp, "default") != 0)
+ fprintf(stderr,
+ _("\nWarning: the fs_type %s is not "
+ "defined in mke2fs.conf\n\n"),
+ cp);
+ }
+ if (t)
+ cp = t+1;
+ else
+ break;
+ }
+ free(parse_str);
+ free(profile_type);
+ if (is_hurd)
+ push_string(&list, "hurd");
+ return (list.list);
+}
+
+static char *get_string_from_profile(char **types, const char *opt,
+ const char *def_val)
+{
+ char *ret = 0;
+ int i;
+
+ for (i=0; types[i]; i++);
+ for (i-=1; i >=0 ; i--) {
+ profile_get_string(profile, "fs_types", types[i],
+ opt, 0, &ret);
+ if (ret)
+ return ret;
+ }
+ profile_get_string(profile, "defaults", opt, 0, def_val, &ret);
+ return (ret);
+}
+
+static int get_int_from_profile(char **types, const char *opt, int def_val)
+{
+ int ret;
+ char **cpp;
+
+ profile_get_integer(profile, "defaults", opt, 0, def_val, &ret);
+ for (cpp = types; *cpp; cpp++)
+ profile_get_integer(profile, "fs_types", *cpp, opt, ret, &ret);
+ return ret;
+}
+
+static double get_double_from_profile(char **types, const char *opt,
+ double def_val)
+{
+ double ret;
+ char **cpp;
+
+ profile_get_double(profile, "defaults", opt, 0, def_val, &ret);
+ for (cpp = types; *cpp; cpp++)
+ profile_get_double(profile, "fs_types", *cpp, opt, ret, &ret);
+ return ret;
+}
+
+static int get_bool_from_profile(char **types, const char *opt, int def_val)
+{
+ int ret;
+ char **cpp;
+
+ profile_get_boolean(profile, "defaults", opt, 0, def_val, &ret);
+ for (cpp = types; *cpp; cpp++)
+ profile_get_boolean(profile, "fs_types", *cpp, opt, ret, &ret);
+ return ret;
+}
+
+extern const char *mke2fs_default_profile;
+static const char *default_files[] = { "<default>", 0 };
+
+#ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY
+/*
+ * Sets the geometry of a device (stripe/stride), and returns the
+ * device's alignment offset, if any, or a negative error.
+ */
+static int get_device_geometry(const char *file,
+ struct ext2_super_block *fs_param,
+ int psector_size)
+{
+ int rc = -1;
+ int blocksize;
+ blkid_probe pr;
+ blkid_topology tp;
+ unsigned long min_io;
+ unsigned long opt_io;
+ struct stat statbuf;
+
+ /* Nothing to do for a regular file */
+ if (!stat(file, &statbuf) && S_ISREG(statbuf.st_mode))
+ return 0;
+
+ pr = blkid_new_probe_from_filename(file);
+ if (!pr)
+ goto out;
+
+ tp = blkid_probe_get_topology(pr);
+ if (!tp)
+ goto out;
+
+ min_io = blkid_topology_get_minimum_io_size(tp);
+ opt_io = blkid_topology_get_optimal_io_size(tp);
+ blocksize = EXT2_BLOCK_SIZE(fs_param);
+ if ((min_io == 0) && (psector_size > blocksize))
+ min_io = psector_size;
+ if ((opt_io == 0) && min_io)
+ opt_io = min_io;
+ if ((opt_io == 0) && (psector_size > blocksize))
+ opt_io = psector_size;
+
+ /* setting stripe/stride to blocksize is pointless */
+ if (min_io > blocksize)
+ fs_param->s_raid_stride = min_io / blocksize;
+ if (opt_io > blocksize)
+ fs_param->s_raid_stripe_width = opt_io / blocksize;
+
+ rc = blkid_topology_get_alignment_offset(tp);
+out:
+ blkid_free_probe(pr);
+ return rc;
+}
+#endif
+
+static void PRS(int argc, char *argv[])
+{
+ int b, c;
+ int cluster_size = 0;
+ char *tmp, **cpp;
+ int blocksize = 0;
+ int inode_ratio = 0;
+ int inode_size = 0;
+ unsigned long flex_bg_size = 0;
+ double reserved_ratio = -1.0;
+ int lsector_size = 0, psector_size = 0;
+ int show_version_only = 0;
+ unsigned long long num_inodes = 0; /* unsigned long long to catch too-large input */
+ errcode_t retval;
+ char * oldpath = getenv("PATH");
+ char * extended_opts = 0;
+ char * fs_type = 0;
+ char * usage_types = 0;
+ blk64_t dev_size;
+ /*
+ * NOTE: A few words about fs_blocks_count and blocksize:
+ *
+ * Initially, blocksize is set to zero, which implies 1024.
+ * If -b is specified, blocksize is updated to the user's value.
+ *
+ * Next, the device size or the user's "blocks" command line argument
+ * is used to set fs_blocks_count; the units are blocksize.
+ *
+ * Later, if blocksize hasn't been set and the profile specifies a
+ * blocksize, then blocksize is updated and fs_blocks_count is scaled
+ * appropriately. Note the change in units!
+ *
+ * Finally, we complain about fs_blocks_count > 2^32 on a non-64bit fs.
+ */
+ blk64_t fs_blocks_count = 0;
+#ifdef __linux__
+ struct utsname ut;
+#endif
+ long sysval;
+ int s_opt = -1, r_opt = -1;
+ char *fs_features = 0;
+ int use_bsize;
+ char *newpath;
+ int pathlen = sizeof(PATH_SET) + 1;
+
+ if (oldpath)
+ pathlen += strlen(oldpath);
+ newpath = malloc(pathlen);
+ if (!newpath) {
+ fprintf(stderr, "%s",
+ _("Couldn't allocate memory for new PATH.\n"));
+ exit(1);
+ }
+ strcpy(newpath, PATH_SET);
+
+ /* Update our PATH to include /sbin */
+ if (oldpath) {
+ strcat (newpath, ":");
+ strcat (newpath, oldpath);
+ }
+ putenv (newpath);
+
+ tmp = getenv("MKE2FS_SYNC");
+ if (tmp)
+ sync_kludge = atoi(tmp);
+
+ /* Determine the system page size if possible */
+#ifdef HAVE_SYSCONF
+#if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
+#define _SC_PAGESIZE _SC_PAGE_SIZE
+#endif
+#ifdef _SC_PAGESIZE
+ sysval = sysconf(_SC_PAGESIZE);
+ if (sysval > 0)
+ sys_page_size = sysval;
+#endif /* _SC_PAGESIZE */
+#endif /* HAVE_SYSCONF */
+
+ if ((tmp = getenv("MKE2FS_CONFIG")) != NULL)
+ config_fn[0] = tmp;
+ profile_set_syntax_err_cb(syntax_err_report);
+ retval = profile_init(config_fn, &profile);
+ if (retval == ENOENT) {
+ retval = profile_init(default_files, &profile);
+ if (retval)
+ goto profile_error;
+ retval = profile_set_default(profile, mke2fs_default_profile);
+ if (retval)
+ goto profile_error;
+ } else if (retval) {
+profile_error:
+ fprintf(stderr, _("Couldn't init profile successfully"
+ " (error: %ld).\n"), retval);
+ exit(1);
+ }
+
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+ add_error_table(&et_ext2_error_table);
+ add_error_table(&et_prof_error_table);
+ memset(&fs_param, 0, sizeof(struct ext2_super_block));
+ fs_param.s_rev_level = 1; /* Create revision 1 filesystems now */
+
+#ifdef __linux__
+ if (uname(&ut)) {
+ perror("uname");
+ exit(1);
+ }
+ linux_version_code = parse_version_number(ut.release);
+ if (linux_version_code && linux_version_code < (2*65536 + 2*256))
+ fs_param.s_rev_level = 0;
+#endif
+
+ if (argc && *argv) {
+ program_name = get_progname(*argv);
+
+ /* If called as mkfs.ext3, create a journal inode */
+ if (!strcmp(program_name, "mkfs.ext3") ||
+ !strcmp(program_name, "mke3fs"))
+ journal_size = -1;
+ }
+
+ while ((c = getopt (argc, argv,
+ "b:cg:i:jl:m:no:qr:s:t:vC:DE:FG:I:J:KL:M:N:O:R:ST:U:V")) != EOF) {
+ switch (c) {
+ case 'b':
+ blocksize = parse_num_blocks2(optarg, -1);
+ b = (blocksize > 0) ? blocksize : -blocksize;
+ if (b < EXT2_MIN_BLOCK_SIZE ||
+ b > EXT2_MAX_BLOCK_SIZE) {
+ com_err(program_name, 0,
+ _("invalid block size - %s"), optarg);
+ exit(1);
+ }
+ if (blocksize > 4096)
+ fprintf(stderr, _("Warning: blocksize %d not "
+ "usable on most systems.\n"),
+ blocksize);
+ if (blocksize > 0)
+ fs_param.s_log_block_size =
+ int_log2(blocksize >>
+ EXT2_MIN_BLOCK_LOG_SIZE);
+ break;
+ case 'c': /* Check for bad blocks */
+ cflag++;
+ break;
+ case 'C':
+ cluster_size = parse_num_blocks2(optarg, -1);
+ if (cluster_size <= EXT2_MIN_CLUSTER_SIZE ||
+ cluster_size > EXT2_MAX_CLUSTER_SIZE) {
+ com_err(program_name, 0,
+ _("invalid cluster size - %s"),
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'D':
+ direct_io = 1;
+ break;
+ case 'R':
+ com_err(program_name, 0, "%s",
+ _("'-R' is deprecated, use '-E' instead"));
+ /* fallthrough */
+ case 'E':
+ extended_opts = optarg;
+ break;
+ case 'F':
+ force++;
+ break;
+ case 'g':
+ fs_param.s_blocks_per_group = strtoul(optarg, &tmp, 0);
+ if (*tmp) {
+ com_err(program_name, 0, "%s",
+ _("Illegal number for blocks per group"));
+ exit(1);
+ }
+ if ((fs_param.s_blocks_per_group % 8) != 0) {
+ com_err(program_name, 0, "%s",
+ _("blocks per group must be multiple of 8"));
+ exit(1);
+ }
+ break;
+ case 'G':
+ flex_bg_size = strtoul(optarg, &tmp, 0);
+ if (*tmp) {
+ com_err(program_name, 0, "%s",
+ _("Illegal number for flex_bg size"));
+ exit(1);
+ }
+ if (flex_bg_size < 1 ||
+ (flex_bg_size & (flex_bg_size-1)) != 0) {
+ com_err(program_name, 0, "%s",
+ _("flex_bg size must be a power of 2"));
+ exit(1);
+ }
+ break;
+ case 'i':
+ inode_ratio = strtoul(optarg, &tmp, 0);
+ if (inode_ratio < EXT2_MIN_BLOCK_SIZE ||
+ inode_ratio > EXT2_MAX_BLOCK_SIZE * 1024 ||
+ *tmp) {
+ com_err(program_name, 0,
+ _("invalid inode ratio %s (min %d/max %d)"),
+ optarg, EXT2_MIN_BLOCK_SIZE,
+ EXT2_MAX_BLOCK_SIZE * 1024);
+ exit(1);
+ }
+ break;
+ case 'I':
+ inode_size = strtoul(optarg, &tmp, 0);
+ if (*tmp) {
+ com_err(program_name, 0,
+ _("invalid inode size - %s"), optarg);
+ exit(1);
+ }
+ break;
+ case 'j':
+ if (!journal_size)
+ journal_size = -1;
+ break;
+ case 'J':
+ parse_journal_opts(optarg);
+ break;
+ case 'K':
+ fprintf(stderr, "%s",
+ _("Warning: -K option is deprecated and "
+ "should not be used anymore. Use "
+ "\'-E nodiscard\' extended option "
+ "instead!\n"));
+ discard = 0;
+ break;
+ case 'l':
+ bad_blocks_filename = realloc(bad_blocks_filename,
+ strlen(optarg) + 1);
+ if (!bad_blocks_filename) {
+ com_err(program_name, ENOMEM, "%s",
+ _("in malloc for bad_blocks_filename"));
+ exit(1);
+ }
+ strcpy(bad_blocks_filename, optarg);
+ break;
+ case 'L':
+ volume_label = optarg;
+ break;
+ case 'm':
+ reserved_ratio = strtod(optarg, &tmp);
+ if ( *tmp || reserved_ratio > 50 ||
+ reserved_ratio < 0) {
+ com_err(program_name, 0,
+ _("invalid reserved blocks percent - %s"),
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'M':
+ mount_dir = optarg;
+ break;
+ case 'n':
+ noaction++;
+ break;
+ case 'N':
+ num_inodes = strtoul(optarg, &tmp, 0);
+ if (*tmp) {
+ com_err(program_name, 0,
+ _("bad num inodes - %s"), optarg);
+ exit(1);
+ }
+ break;
+ case 'o':
+ creator_os = optarg;
+ break;
+ case 'O':
+ fs_features = optarg;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'r':
+ r_opt = strtoul(optarg, &tmp, 0);
+ if (*tmp) {
+ com_err(program_name, 0,
+ _("bad revision level - %s"), optarg);
+ exit(1);
+ }
+ fs_param.s_rev_level = r_opt;
+ break;
+ case 's': /* deprecated */
+ s_opt = atoi(optarg);
+ break;
+ case 'S':
+ super_only = 1;
+ break;
+ case 't':
+ if (fs_type) {
+ com_err(program_name, 0, "%s",
+ _("The -t option may only be used once"));
+ exit(1);
+ }
+ fs_type = strdup(optarg);
+ break;
+ case 'T':
+ if (usage_types) {
+ com_err(program_name, 0, "%s",
+ _("The -T option may only be used once"));
+ exit(1);
+ }
+ usage_types = strdup(optarg);
+ break;
+ case 'U':
+ fs_uuid = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'V':
+ /* Print version number and exit */
+ show_version_only++;
+ break;
+ default:
+ usage();
+ }
+ }
+ if ((optind == argc) && !show_version_only)
+ usage();
+ device_name = argv[optind++];
+
+ if (!quiet || show_version_only)
+ fprintf (stderr, "mke2fs %s (%s)\n", E2FSPROGS_VERSION,
+ E2FSPROGS_DATE);
+
+ if (show_version_only) {
+ fprintf(stderr, _("\tUsing %s\n"),
+ error_message(EXT2_ET_BASE));
+ exit(0);
+ }
+
+ /*
+ * If there's no blocksize specified and there is a journal
+ * device, use it to figure out the blocksize
+ */
+ if (blocksize <= 0 && journal_device) {
+ ext2_filsys jfs;
+ io_manager io_ptr;
+
+#ifdef CONFIG_TESTIO_DEBUG
+ if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
+ io_ptr = test_io_manager;
+ test_io_backing_manager = unix_io_manager;
+ } else
+#endif
+ io_ptr = unix_io_manager;
+ retval = ext2fs_open(journal_device,
+ EXT2_FLAG_JOURNAL_DEV_OK, 0,
+ 0, io_ptr, &jfs);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while trying to open journal device %s\n"),
+ journal_device);
+ exit(1);
+ }
+ if ((blocksize < 0) && (jfs->blocksize < (unsigned) (-blocksize))) {
+ com_err(program_name, 0,
+ _("Journal dev blocksize (%d) smaller than "
+ "minimum blocksize %d\n"), jfs->blocksize,
+ -blocksize);
+ exit(1);
+ }
+ blocksize = jfs->blocksize;
+ printf(_("Using journal device's blocksize: %d\n"), blocksize);
+ fs_param.s_log_block_size =
+ int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
+ ext2fs_close(jfs);
+ }
+
+ if (optind < argc) {
+ fs_blocks_count = parse_num_blocks2(argv[optind++],
+ fs_param.s_log_block_size);
+ if (!fs_blocks_count) {
+ com_err(program_name, 0,
+ _("invalid blocks '%s' on device '%s'"),
+ argv[optind - 1], device_name);
+ exit(1);
+ }
+ }
+ if (optind < argc)
+ usage();
+
+ if (!force)
+ check_plausibility(device_name);
+ check_mount(device_name, force, _("filesystem"));
+
+ /* Determine the size of the device (if possible) */
+ if (noaction && fs_blocks_count) {
+ dev_size = fs_blocks_count;
+ retval = 0;
+ } else
+ retval = ext2fs_get_device_size2(device_name,
+ EXT2_BLOCK_SIZE(&fs_param),
+ &dev_size);
+
+ if (retval && (retval != EXT2_ET_UNIMPLEMENTED)) {
+ com_err(program_name, retval, "%s",
+ _("while trying to determine filesystem size"));
+ exit(1);
+ }
+ if (!fs_blocks_count) {
+ if (retval == EXT2_ET_UNIMPLEMENTED) {
+ com_err(program_name, 0, "%s",
+ _("Couldn't determine device size; you "
+ "must specify\nthe size of the "
+ "filesystem\n"));
+ exit(1);
+ } else {
+ if (dev_size == 0) {
+ com_err(program_name, 0, "%s",
+ _("Device size reported to be zero. "
+ "Invalid partition specified, or\n\t"
+ "partition table wasn't reread "
+ "after running fdisk, due to\n\t"
+ "a modified partition being busy "
+ "and in use. You may need to reboot\n\t"
+ "to re-read your partition table.\n"
+ ));
+ exit(1);
+ }
+ fs_blocks_count = dev_size;
+ if (sys_page_size > EXT2_BLOCK_SIZE(&fs_param))
+ fs_blocks_count &= ~((blk64_t) ((sys_page_size /
+ EXT2_BLOCK_SIZE(&fs_param))-1));
+ }
+ } else if (!force && (fs_blocks_count > dev_size)) {
+ com_err(program_name, 0, "%s",
+ _("Filesystem larger than apparent device size."));
+ proceed_question();
+ }
+
+ if (!fs_type)
+ profile_get_string(profile, "devices", device_name,
+ "fs_type", 0, &fs_type);
+ if (!usage_types)
+ profile_get_string(profile, "devices", device_name,
+ "usage_types", 0, &usage_types);
+
+ /*
+ * We have the file system (or device) size, so we can now
+ * determine the appropriate file system types so the fs can
+ * be appropriately configured.
+ */
+ fs_types = parse_fs_type(fs_type, usage_types, &fs_param,
+ fs_blocks_count ? fs_blocks_count : dev_size,
+ argv[0]);
+ if (!fs_types) {
+ fprintf(stderr, "%s", _("Failed to parse fs types list\n"));
+ exit(1);
+ }
+
+ /* Figure out what features should be enabled */
+
+ tmp = NULL;
+ if (fs_param.s_rev_level != EXT2_GOOD_OLD_REV) {
+ tmp = get_string_from_profile(fs_types, "base_features",
+ "sparse_super,filetype,resize_inode,dir_index");
+ edit_feature(tmp, &fs_param.s_feature_compat);
+ free(tmp);
+
+ /* And which mount options as well */
+ tmp = get_string_from_profile(fs_types, "default_mntopts",
+ "acl,user_xattr");
+ edit_mntopts(tmp, &fs_param.s_default_mount_opts);
+ if (tmp)
+ free(tmp);
+
+ for (cpp = fs_types; *cpp; cpp++) {
+ tmp = NULL;
+ profile_get_string(profile, "fs_types", *cpp,
+ "features", "", &tmp);
+ if (tmp && *tmp)
+ edit_feature(tmp, &fs_param.s_feature_compat);
+ if (tmp)
+ free(tmp);
+ }
+ tmp = get_string_from_profile(fs_types, "default_features",
+ "");
+ }
+ edit_feature(fs_features ? fs_features : tmp,
+ &fs_param.s_feature_compat);
+ if (tmp)
+ free(tmp);
+
+ /* Get the hardware sector sizes, if available */
+ retval = ext2fs_get_device_sectsize(device_name, &lsector_size);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while trying to determine hardware sector size"));
+ exit(1);
+ }
+ retval = ext2fs_get_device_phys_sectsize(device_name, &psector_size);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while trying to determine physical sector size"));
+ exit(1);
+ }
+
+ tmp = getenv("MKE2FS_DEVICE_SECTSIZE");
+ if (tmp != NULL)
+ lsector_size = atoi(tmp);
+ tmp = getenv("MKE2FS_DEVICE_PHYS_SECTSIZE");
+ if (tmp != NULL)
+ psector_size = atoi(tmp);
+
+ /* Older kernels may not have physical/logical distinction */
+ if (!psector_size)
+ psector_size = lsector_size;
+
+ if (blocksize <= 0) {
+ use_bsize = get_int_from_profile(fs_types, "blocksize", 4096);
+
+ if (use_bsize == -1) {
+ use_bsize = sys_page_size;
+ if ((linux_version_code < (2*65536 + 6*256)) &&
+ (use_bsize > 4096))
+ use_bsize = 4096;
+ }
+ if (lsector_size && use_bsize < lsector_size)
+ use_bsize = lsector_size;
+ if ((blocksize < 0) && (use_bsize < (-blocksize)))
+ use_bsize = -blocksize;
+ blocksize = use_bsize;
+ fs_blocks_count /= (blocksize / 1024);
+ } else {
+ if (blocksize < lsector_size) { /* Impossible */
+ com_err(program_name, EINVAL, "%s",
+ _("while setting blocksize; too small "
+ "for device\n"));
+ exit(1);
+ } else if ((blocksize < psector_size) &&
+ (psector_size <= sys_page_size)) { /* Suboptimal */
+ fprintf(stderr, _("Warning: specified blocksize %d is "
+ "less than device physical sectorsize %d\n"),
+ blocksize, psector_size);
+ }
+ }
+
+ fs_param.s_log_block_size =
+ int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
+
+ /*
+ * We now need to do a sanity check of fs_blocks_count for
+ * 32-bit vs 64-bit block number support.
+ */
+ if ((fs_blocks_count > MAX_32_NUM) &&
+ !(fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) &&
+ get_bool_from_profile(fs_types, "auto_64-bit_support", 0)) {
+ fs_param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_64BIT;
+ fs_param.s_feature_compat &= ~EXT2_FEATURE_COMPAT_RESIZE_INODE;
+ }
+ if ((fs_blocks_count > MAX_32_NUM) &&
+ !(fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)) {
+ fprintf(stderr, _("%s: Size of device (0x%llx blocks) %s "
+ "too big to be expressed\n\t"
+ "in 32 bits using a blocksize of %d.\n"),
+ program_name, fs_blocks_count, device_name,
+ EXT2_BLOCK_SIZE(&fs_param));
+ exit(1);
+ }
+
+ ext2fs_blocks_count_set(&fs_param, fs_blocks_count);
+
+ if (fs_param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+ fs_types[0] = strdup("journal");
+ fs_types[1] = 0;
+ }
+
+ if (verbose) {
+ fputs(_("fs_types for mke2fs.conf resolution: "), stdout);
+ print_str_list(fs_types);
+ }
+
+ if (r_opt == EXT2_GOOD_OLD_REV &&
+ (fs_param.s_feature_compat || fs_param.s_feature_incompat ||
+ fs_param.s_feature_ro_compat)) {
+ fprintf(stderr, "%s", _("Filesystem features not supported "
+ "with revision 0 filesystems\n"));
+ exit(1);
+ }
+
+ if (s_opt > 0) {
+ if (r_opt == EXT2_GOOD_OLD_REV) {
+ fprintf(stderr, "%s",
+ _("Sparse superblocks not supported "
+ "with revision 0 filesystems\n"));
+ exit(1);
+ }
+ fs_param.s_feature_ro_compat |=
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+ } else if (s_opt == 0)
+ fs_param.s_feature_ro_compat &=
+ ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+
+ if (journal_size != 0) {
+ if (r_opt == EXT2_GOOD_OLD_REV) {
+ fprintf(stderr, "%s", _("Journals not supported with "
+ "revision 0 filesystems\n"));
+ exit(1);
+ }
+ fs_param.s_feature_compat |=
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ }
+
+ /* Get reserved_ratio from profile if not specified on cmd line. */
+ if (reserved_ratio < 0.0) {
+ reserved_ratio = get_double_from_profile(
+ fs_types, "reserved_ratio", 5.0);
+ if (reserved_ratio > 50 || reserved_ratio < 0) {
+ com_err(program_name, 0,
+ _("invalid reserved blocks percent - %lf"),
+ reserved_ratio);
+ exit(1);
+ }
+ }
+
+ if (fs_param.s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+ reserved_ratio = 0;
+ fs_param.s_feature_incompat = EXT3_FEATURE_INCOMPAT_JOURNAL_DEV;
+ fs_param.s_feature_compat = 0;
+ fs_param.s_feature_ro_compat = 0;
+ }
+
+ /* Check the user's mkfs options for 64bit */
+ if ((fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) &&
+ !(fs_param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)) {
+ printf("%s", _("Extents MUST be enabled for a 64-bit "
+ "filesystem. Pass -O extents to rectify.\n"));
+ exit(1);
+ }
+
+ /* Set first meta blockgroup via an environment variable */
+ /* (this is mostly for debugging purposes) */
+ if ((fs_param.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) &&
+ ((tmp = getenv("MKE2FS_FIRST_META_BG"))))
+ fs_param.s_first_meta_bg = atoi(tmp);
+ if (fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_BIGALLOC) {
+ if (!cluster_size)
+ cluster_size = get_int_from_profile(fs_types,
+ "cluster_size",
+ blocksize*16);
+ fs_param.s_log_cluster_size =
+ int_log2(cluster_size >> EXT2_MIN_CLUSTER_LOG_SIZE);
+ if (fs_param.s_log_cluster_size &&
+ fs_param.s_log_cluster_size < fs_param.s_log_block_size) {
+ com_err(program_name, 0, "%s",
+ _("The cluster size may not be "
+ "smaller than the block size.\n"));
+ exit(1);
+ }
+ } else if (cluster_size) {
+ com_err(program_name, 0, "%s",
+ _("specifying a cluster size requires the "
+ "bigalloc feature"));
+ exit(1);
+ } else
+ fs_param.s_log_cluster_size = fs_param.s_log_block_size;
+
+ if (inode_ratio == 0) {
+ inode_ratio = get_int_from_profile(fs_types, "inode_ratio",
+ 8192);
+ if (inode_ratio < blocksize)
+ inode_ratio = blocksize;
+ if (inode_ratio < EXT2_CLUSTER_SIZE(&fs_param))
+ inode_ratio = EXT2_CLUSTER_SIZE(&fs_param);
+ }
+
+#ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY
+ retval = get_device_geometry(device_name, &fs_param, psector_size);
+ if (retval < 0) {
+ fprintf(stderr,
+ _("warning: Unable to get device geometry for %s\n"),
+ device_name);
+ } else if (retval) {
+ printf(_("%s alignment is offset by %lu bytes.\n"),
+ device_name, retval);
+ printf(_("This may result in very poor performance, "
+ "(re)-partitioning suggested.\n"));
+ }
+#endif
+
+ blocksize = EXT2_BLOCK_SIZE(&fs_param);
+
+ /*
+ * Initialize s_desc_size so that the parse_extended_opts()
+ * can correctly handle "-E resize=NNN" if the 64-bit option
+ * is set.
+ */
+ if (fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
+ fs_param.s_desc_size = EXT2_MIN_DESC_SIZE_64BIT;
+
+ /* This check should happen beyond the last assignment to blocksize */
+ if (blocksize > sys_page_size) {
+ if (!force) {
+ com_err(program_name, 0,
+ _("%d-byte blocks too big for system (max %d)"),
+ blocksize, sys_page_size);
+ proceed_question();
+ }
+ fprintf(stderr, _("Warning: %d-byte blocks too big for system "
+ "(max %d), forced to continue\n"),
+ blocksize, sys_page_size);
+ }
+
+ lazy_itable_init = 0;
+ if (access("/sys/fs/ext4/features/lazy_itable_init", R_OK) == 0)
+ lazy_itable_init = 1;
+
+ lazy_itable_init = get_bool_from_profile(fs_types,
+ "lazy_itable_init",
+ lazy_itable_init);
+ discard = get_bool_from_profile(fs_types, "discard" , discard);
+ journal_flags |= get_bool_from_profile(fs_types,
+ "lazy_journal_init", 0) ?
+ EXT2_MKJOURNAL_LAZYINIT : 0;
+ journal_flags |= EXT2_MKJOURNAL_NO_MNT_CHECK;
+
+ /* Get options from profile */
+ for (cpp = fs_types; *cpp; cpp++) {
+ tmp = NULL;
+ profile_get_string(profile, "fs_types", *cpp, "options", "", &tmp);
+ if (tmp && *tmp)
+ parse_extended_opts(&fs_param, tmp);
+ free(tmp);
+ }
+
+ if (extended_opts)
+ parse_extended_opts(&fs_param, extended_opts);
+
+ /* Can't support bigalloc feature without extents feature */
+ if ((fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_BIGALLOC) &&
+ !(fs_param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)) {
+ com_err(program_name, 0, "%s",
+ _("Can't support bigalloc feature without "
+ "extents feature"));
+ exit(1);
+ }
+
+ if ((fs_param.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) &&
+ (fs_param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
+ fprintf(stderr, "%s", _("The resize_inode and meta_bg "
+ "features are not compatible.\n"
+ "They can not be both enabled "
+ "simultaneously.\n"));
+ exit(1);
+ }
+
+ if (!quiet &&
+ (fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+ fprintf(stderr, "%s", _("\nWarning: the bigalloc feature is "
+ "still under development\n"
+ "See https://ext4.wiki.kernel.org/"
+ "index.php/Bigalloc for more information\n\n"));
+
+ if (!quiet &&
+ (fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_QUOTA))
+ fprintf(stderr, "%s", _("\nWarning: the quota feature is "
+ "still under development\n"
+ "See https://ext4.wiki.kernel.org/"
+ "index.php/Quota for more information\n\n"));
+
+ /* Since sparse_super is the default, we would only have a problem
+ * here if it was explicitly disabled.
+ */
+ if ((fs_param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
+ !(fs_param.s_feature_ro_compat&EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+ com_err(program_name, 0, "%s",
+ _("reserved online resize blocks not supported "
+ "on non-sparse filesystem"));
+ exit(1);
+ }
+
+ if (fs_param.s_blocks_per_group) {
+ if (fs_param.s_blocks_per_group < 256 ||
+ fs_param.s_blocks_per_group > 8 * (unsigned) blocksize) {
+ com_err(program_name, 0, "%s",
+ _("blocks per group count out of range"));
+ exit(1);
+ }
+ }
+
+ /*
+ * If the bigalloc feature is enabled, then the -g option will
+ * specify the number of clusters per group.
+ */
+ if (fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_BIGALLOC) {
+ fs_param.s_clusters_per_group = fs_param.s_blocks_per_group;
+ fs_param.s_blocks_per_group = 0;
+ }
+
+ if (inode_size == 0)
+ inode_size = get_int_from_profile(fs_types, "inode_size", 0);
+ if (!flex_bg_size && (fs_param.s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_FLEX_BG))
+ flex_bg_size = get_int_from_profile(fs_types,
+ "flex_bg_size", 16);
+ if (flex_bg_size) {
+ if (!(fs_param.s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+ com_err(program_name, 0, "%s",
+ _("Flex_bg feature not enabled, so "
+ "flex_bg size may not be specified"));
+ exit(1);
+ }
+ fs_param.s_log_groups_per_flex = int_log2(flex_bg_size);
+ }
+
+ if (inode_size && fs_param.s_rev_level >= EXT2_DYNAMIC_REV) {
+ if (inode_size < EXT2_GOOD_OLD_INODE_SIZE ||
+ inode_size > EXT2_BLOCK_SIZE(&fs_param) ||
+ inode_size & (inode_size - 1)) {
+ com_err(program_name, 0,
+ _("invalid inode size %d (min %d/max %d)"),
+ inode_size, EXT2_GOOD_OLD_INODE_SIZE,
+ blocksize);
+ exit(1);
+ }
+ fs_param.s_inode_size = inode_size;
+ }
+
+ /* Make sure number of inodes specified will fit in 32 bits */
+ if (num_inodes == 0) {
+ unsigned long long n;
+ n = ext2fs_blocks_count(&fs_param) * blocksize / inode_ratio;
+ if (n > MAX_32_NUM) {
+ if (fs_param.s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_64BIT)
+ num_inodes = MAX_32_NUM;
+ else {
+ com_err(program_name, 0,
+ _("too many inodes (%llu), raise "
+ "inode ratio?"), n);
+ exit(1);
+ }
+ }
+ } else if (num_inodes > MAX_32_NUM) {
+ com_err(program_name, 0,
+ _("too many inodes (%llu), specify < 2^32 inodes"),
+ num_inodes);
+ exit(1);
+ }
+ /*
+ * Calculate number of inodes based on the inode ratio
+ */
+ fs_param.s_inodes_count = num_inodes ? num_inodes :
+ (ext2fs_blocks_count(&fs_param) * blocksize) / inode_ratio;
+
+ if ((((unsigned long long)fs_param.s_inodes_count) *
+ (inode_size ? inode_size : EXT2_GOOD_OLD_INODE_SIZE)) >=
+ ((ext2fs_blocks_count(&fs_param)) *
+ EXT2_BLOCK_SIZE(&fs_param))) {
+ com_err(program_name, 0, _("inode_size (%u) * inodes_count "
+ "(%u) too big for a\n\t"
+ "filesystem with %llu blocks, "
+ "specify higher inode_ratio (-i)\n\t"
+ "or lower inode count (-N).\n"),
+ inode_size ? inode_size : EXT2_GOOD_OLD_INODE_SIZE,
+ fs_param.s_inodes_count,
+ (unsigned long long) ext2fs_blocks_count(&fs_param));
+ exit(1);
+ }
+
+ /*
+ * Calculate number of blocks to reserve
+ */
+ ext2fs_r_blocks_count_set(&fs_param, reserved_ratio *
+ ext2fs_blocks_count(&fs_param) / 100.0);
+
+ free(fs_type);
+ free(usage_types);
+}
+
+static int should_do_undo(const char *name)
+{
+ errcode_t retval;
+ io_channel channel;
+ __u16 s_magic;
+ struct ext2_super_block super;
+ io_manager manager = unix_io_manager;
+ int csum_flag, force_undo;
+
+ csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(&fs_param,
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+ force_undo = get_int_from_profile(fs_types, "force_undo", 0);
+ if (!force_undo && (!csum_flag || !lazy_itable_init))
+ return 0;
+
+ retval = manager->open(name, IO_FLAG_EXCLUSIVE, &channel);
+ if (retval) {
+ /*
+ * We don't handle error cases instead we
+ * declare that the file system doesn't exist
+ * and let the rest of mke2fs take care of
+ * error
+ */
+ retval = 0;
+ goto open_err_out;
+ }
+
+ io_channel_set_blksize(channel, SUPERBLOCK_OFFSET);
+ retval = io_channel_read_blk64(channel, 1, -SUPERBLOCK_SIZE, &super);
+ if (retval) {
+ retval = 0;
+ goto err_out;
+ }
+
+#if defined(WORDS_BIGENDIAN)
+ s_magic = ext2fs_swab16(super.s_magic);
+#else
+ s_magic = super.s_magic;
+#endif
+
+ if (s_magic == EXT2_SUPER_MAGIC)
+ retval = 1;
+
+err_out:
+ io_channel_close(channel);
+
+open_err_out:
+
+ return retval;
+}
+
+static int mke2fs_setup_tdb(const char *name, io_manager *io_ptr)
+{
+ errcode_t retval = ENOMEM;
+ char *tdb_dir = NULL, *tdb_file = NULL;
+ char *dev_name, *tmp_name;
+ int free_tdb_dir = 0;
+
+ /*
+ * Configuration via a conf file would be
+ * nice
+ */
+ tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
+ if (!tdb_dir) {
+ profile_get_string(profile, "defaults",
+ "undo_dir", 0, "/var/lib/e2fsprogs",
+ &tdb_dir);
+ free_tdb_dir = 1;
+ }
+
+ if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
+ access(tdb_dir, W_OK)) {
+ if (free_tdb_dir)
+ free(tdb_dir);
+ return 0;
+ }
+
+ tmp_name = strdup(name);
+ if (!tmp_name)
+ goto errout;
+ dev_name = basename(tmp_name);
+ tdb_file = malloc(strlen(tdb_dir) + 8 + strlen(dev_name) + 7 + 1);
+ if (!tdb_file) {
+ free(tmp_name);
+ goto errout;
+ }
+ sprintf(tdb_file, "%s/mke2fs-%s.e2undo", tdb_dir, dev_name);
+ free(tmp_name);
+
+ if (!access(tdb_file, F_OK)) {
+ if (unlink(tdb_file) < 0) {
+ retval = errno;
+ goto errout;
+ }
+ }
+
+ set_undo_io_backing_manager(*io_ptr);
+ *io_ptr = undo_io_manager;
+ retval = set_undo_io_backup_file(tdb_file);
+ if (retval)
+ goto errout;
+ printf(_("Overwriting existing filesystem; this can be undone "
+ "using the command:\n"
+ " e2undo %s %s\n\n"), tdb_file, name);
+
+ if (free_tdb_dir)
+ free(tdb_dir);
+ free(tdb_file);
+ return 0;
+
+errout:
+ if (free_tdb_dir)
+ free(tdb_dir);
+ free(tdb_file);
+ com_err(program_name, retval, "%s",
+ _("while trying to setup undo file\n"));
+ return retval;
+}
+
+static int mke2fs_discard_device(ext2_filsys fs)
+{
+ struct ext2fs_numeric_progress_struct progress;
+ blk64_t blocks = ext2fs_blocks_count(fs->super);
+ blk64_t count = DISCARD_STEP_MB;
+ blk64_t cur;
+ int retval = 0;
+
+ /*
+ * Let's try if discard really works on the device, so
+ * we do not print numeric progress resulting in failure
+ * afterwards.
+ */
+ retval = io_channel_discard(fs->io, 0, fs->blocksize);
+ if (retval)
+ return retval;
+ cur = fs->blocksize;
+
+ count *= (1024 * 1024);
+ count /= fs->blocksize;
+
+ ext2fs_numeric_progress_init(fs, &progress,
+ _("Discarding device blocks: "),
+ blocks);
+ while (cur < blocks) {
+ ext2fs_numeric_progress_update(fs, &progress, cur);
+
+ if (cur + count > blocks)
+ count = blocks - cur;
+
+ retval = io_channel_discard(fs->io, cur, count);
+ if (retval)
+ break;
+ cur += count;
+ }
+
+ if (retval) {
+ ext2fs_numeric_progress_close(fs, &progress,
+ _("failed - "));
+ if (!quiet)
+ printf("%s\n",error_message(retval));
+ } else
+ ext2fs_numeric_progress_close(fs, &progress,
+ _("done \n"));
+
+ return retval;
+}
+
+static void fix_cluster_bg_counts(ext2_filsys fs)
+{
+ blk64_t cluster, num_clusters, tot_free;
+ unsigned num = 0;
+ int grp_free, num_free, group;
+
+ num_clusters = EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super));
+ tot_free = num_free = group = grp_free = 0;
+ for (cluster = EXT2FS_B2C(fs, fs->super->s_first_data_block);
+ cluster < num_clusters; cluster++) {
+ if (!ext2fs_test_block_bitmap2(fs->block_map,
+ EXT2FS_C2B(fs, cluster))) {
+ grp_free++;
+ tot_free++;
+ }
+ num++;
+ if ((num == fs->super->s_clusters_per_group) ||
+ (cluster == num_clusters-1)) {
+ ext2fs_bg_free_blocks_count_set(fs, group, grp_free);
+ ext2fs_group_desc_csum_set(fs, group);
+ num = 0;
+ grp_free = 0;
+ group++;
+ }
+ }
+ ext2fs_free_blocks_count_set(fs->super, EXT2FS_C2B(fs, tot_free));
+}
+
+static int create_quota_inodes(ext2_filsys fs)
+{
+ quota_ctx_t qctx;
+
+ quota_init_context(&qctx, fs, -1);
+ quota_compute_usage(qctx);
+ quota_write_inode(qctx, quotatype);
+ quota_release_context(&qctx);
+
+ return 0;
+}
+
+int main (int argc, char *argv[])
+{
+ errcode_t retval = 0;
+ ext2_filsys fs;
+ badblocks_list bb_list = 0;
+ unsigned int journal_blocks;
+ unsigned int i, checkinterval;
+ int max_mnt_count;
+ int val, hash_alg;
+ int flags;
+ int old_bitmaps;
+ io_manager io_ptr;
+ char tdb_string[40];
+ char *hash_alg_str;
+ int itable_zeroed = 0;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+ PRS(argc, argv);
+
+#ifdef CONFIG_TESTIO_DEBUG
+ if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
+ io_ptr = test_io_manager;
+ test_io_backing_manager = unix_io_manager;
+ } else
+#endif
+ io_ptr = unix_io_manager;
+
+ if (should_do_undo(device_name)) {
+ retval = mke2fs_setup_tdb(device_name, &io_ptr);
+ if (retval)
+ exit(1);
+ }
+
+ /*
+ * Initialize the superblock....
+ */
+ flags = EXT2_FLAG_EXCLUSIVE;
+ if (direct_io)
+ flags |= EXT2_FLAG_DIRECT_IO;
+ profile_get_boolean(profile, "options", "old_bitmaps", 0, 0,
+ &old_bitmaps);
+ if (!old_bitmaps)
+ flags |= EXT2_FLAG_64BITS;
+ /*
+ * By default, we print how many inode tables or block groups
+ * or whatever we've written so far. The quiet flag disables
+ * this, along with a lot of other output.
+ */
+ if (!quiet)
+ flags |= EXT2_FLAG_PRINT_PROGRESS;
+ retval = ext2fs_initialize(device_name, flags, &fs_param, io_ptr, &fs);
+ if (retval) {
+ com_err(device_name, retval, "%s",
+ _("while setting up superblock"));
+ exit(1);
+ }
+
+ /* Calculate journal blocks */
+ if (!journal_device && ((journal_size) ||
+ (fs_param.s_feature_compat &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL)))
+ journal_blocks = figure_journal_size(journal_size, fs);
+
+ /* Can't undo discard ... */
+ if (!noaction && discard && (io_ptr != undo_io_manager)) {
+ retval = mke2fs_discard_device(fs);
+ if (!retval && io_channel_discard_zeroes_data(fs->io)) {
+ if (verbose)
+ printf("%s",
+ _("Discard succeeded and will return "
+ "0s - skipping inode table wipe\n"));
+ lazy_itable_init = 1;
+ itable_zeroed = 1;
+ }
+ }
+
+ sprintf(tdb_string, "tdb_data_size=%d", fs->blocksize <= 4096 ?
+ 32768 : fs->blocksize * 8);
+ io_channel_set_options(fs->io, tdb_string);
+
+ if (fs_param.s_flags & EXT2_FLAGS_TEST_FILESYS)
+ fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS;
+
+ if ((fs_param.s_feature_incompat &
+ (EXT3_FEATURE_INCOMPAT_EXTENTS|EXT4_FEATURE_INCOMPAT_FLEX_BG)) ||
+ (fs_param.s_feature_ro_compat &
+ (EXT4_FEATURE_RO_COMPAT_HUGE_FILE|EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)))
+ fs->super->s_kbytes_written = 1;
+
+ /*
+ * Wipe out the old on-disk superblock
+ */
+ if (!noaction)
+ zap_sector(fs, 2, 6);
+
+ /*
+ * Parse or generate a UUID for the filesystem
+ */
+ if (fs_uuid) {
+ if (uuid_parse(fs_uuid, fs->super->s_uuid) !=0) {
+ com_err(device_name, 0, "could not parse UUID: %s\n",
+ fs_uuid);
+ exit(1);
+ }
+ } else
+ uuid_generate(fs->super->s_uuid);
+
+ /*
+ * Initialize the directory index variables
+ */
+ hash_alg_str = get_string_from_profile(fs_types, "hash_alg",
+ "half_md4");
+ hash_alg = e2p_string2hash(hash_alg_str);
+ free(hash_alg_str);
+ fs->super->s_def_hash_version = (hash_alg >= 0) ? hash_alg :
+ EXT2_HASH_HALF_MD4;
+ uuid_generate((unsigned char *) fs->super->s_hash_seed);
+
+ /*
+ * Periodic checks can be enabled/disabled via config file.
+ * Note we override the kernel include file's idea of what the default
+ * check interval (never) should be. It's a good idea to check at
+ * least *occasionally*, specially since servers will never rarely get
+ * to reboot, since Linux is so robust these days. :-)
+ *
+ * 180 days (six months) seems like a good value.
+ */
+#ifdef EXT2_DFL_CHECKINTERVAL
+#undef EXT2_DFL_CHECKINTERVAL
+#endif
+#define EXT2_DFL_CHECKINTERVAL (86400L * 180L)
+
+ if (get_bool_from_profile(fs_types, "enable_periodic_fsck", 0)) {
+ fs->super->s_checkinterval = EXT2_DFL_CHECKINTERVAL;
+ fs->super->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
+ /*
+ * Add "jitter" to the superblock's check interval so that we
+ * don't check all the filesystems at the same time. We use a
+ * kludgy hack of using the UUID to derive a random jitter value
+ */
+ for (i = 0, val = 0 ; i < sizeof(fs->super->s_uuid); i++)
+ val += fs->super->s_uuid[i];
+ fs->super->s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;
+ } else
+ fs->super->s_max_mnt_count = -1;
+
+ /*
+ * Override the creator OS, if applicable
+ */
+ if (creator_os && !set_os(fs->super, creator_os)) {
+ com_err (program_name, 0, _("unknown os - %s"), creator_os);
+ exit(1);
+ }
+
+ /*
+ * For the Hurd, we will turn off filetype since it doesn't
+ * support it.
+ */
+ if (fs->super->s_creator_os == EXT2_OS_HURD)
+ fs->super->s_feature_incompat &=
+ ~EXT2_FEATURE_INCOMPAT_FILETYPE;
+
+ /*
+ * Set the volume label...
+ */
+ if (volume_label) {
+ memset(fs->super->s_volume_name, 0,
+ sizeof(fs->super->s_volume_name));
+ strncpy(fs->super->s_volume_name, volume_label,
+ sizeof(fs->super->s_volume_name));
+ }
+
+ /*
+ * Set the last mount directory
+ */
+ if (mount_dir) {
+ memset(fs->super->s_last_mounted, 0,
+ sizeof(fs->super->s_last_mounted));
+ strncpy(fs->super->s_last_mounted, mount_dir,
+ sizeof(fs->super->s_last_mounted));
+ }
+
+ if (!quiet || noaction)
+ show_stats(fs);
+
+ if (noaction)
+ exit(0);
+
+ if (fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+ create_journal_dev(fs);
+ exit(ext2fs_close(fs) ? 1 : 0);
+ }
+
+ if (bad_blocks_filename)
+ read_bb_file(fs, &bb_list, bad_blocks_filename);
+ if (cflag)
+ test_disk(fs, &bb_list);
+
+ handle_bad_blocks(fs, bb_list);
+ fs->stride = fs_stride = fs->super->s_raid_stride;
+ if (!quiet)
+ printf("%s", _("Allocating group tables: "));
+ retval = ext2fs_allocate_tables(fs);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while trying to allocate filesystem tables"));
+ exit(1);
+ }
+ if (!quiet)
+ printf("%s", _("done \n"));
+
+ retval = ext2fs_convert_subcluster_bitmap(fs, &fs->block_map);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("\n\twhile converting subcluster bitmap"));
+ exit(1);
+ }
+
+ if (super_only) {
+ fs->super->s_state |= EXT2_ERROR_FS;
+ fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY);
+ /*
+ * The command "mke2fs -S" is used to recover
+ * corrupted file systems, so do not mark any of the
+ * inodes as unused; we want e2fsck to consider all
+ * inodes as potentially containing recoverable data.
+ */
+ if (fs->super->s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+ for (i = 0; i < fs->group_desc_count; i++)
+ ext2fs_bg_itable_unused_set(fs, i, 0);
+ }
+ } else {
+ /* rsv must be a power of two (64kB is MD RAID sb alignment) */
+ blk64_t rsv = 65536 / fs->blocksize;
+ blk64_t blocks = ext2fs_blocks_count(fs->super);
+ blk64_t start;
+ blk64_t ret_blk;
+
+#ifdef ZAP_BOOTBLOCK
+ zap_sector(fs, 0, 2);
+#endif
+
+ /*
+ * Wipe out any old MD RAID (or other) metadata at the end
+ * of the device. This will also verify that the device is
+ * as large as we think. Be careful with very small devices.
+ */
+ start = (blocks & ~(rsv - 1));
+ if (start > rsv)
+ start -= rsv;
+ if (start > 0)
+ retval = ext2fs_zero_blocks2(fs, start, blocks - start,
+ &ret_blk, NULL);
+
+ if (retval) {
+ com_err(program_name, retval,
+ _("while zeroing block %llu at end of filesystem"),
+ ret_blk);
+ }
+ write_inode_tables(fs, lazy_itable_init, itable_zeroed);
+ create_root_dir(fs);
+ create_lost_and_found(fs);
+ reserve_inodes(fs);
+ create_bad_block_inode(fs, bb_list);
+ if (fs->super->s_feature_compat &
+ EXT2_FEATURE_COMPAT_RESIZE_INODE) {
+ retval = ext2fs_create_resize_inode(fs);
+ if (retval) {
+ com_err("ext2fs_create_resize_inode", retval,
+ "%s",
+ _("while reserving blocks for online resize"));
+ exit(1);
+ }
+ }
+ }
+
+ if (journal_device) {
+ ext2_filsys jfs;
+
+ if (!force)
+ check_plausibility(journal_device);
+ check_mount(journal_device, force, _("journal"));
+
+ retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
+ EXT2_FLAG_JOURNAL_DEV_OK, 0,
+ fs->blocksize, unix_io_manager, &jfs);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while trying to open journal device %s\n"),
+ journal_device);
+ exit(1);
+ }
+ if (!quiet) {
+ printf(_("Adding journal to device %s: "),
+ journal_device);
+ fflush(stdout);
+ }
+ retval = ext2fs_add_journal_device(fs, jfs);
+ if(retval) {
+ com_err (program_name, retval,
+ _("\n\twhile trying to add journal to device %s"),
+ journal_device);
+ exit(1);
+ }
+ if (!quiet)
+ printf("%s", _("done\n"));
+ ext2fs_close(jfs);
+ free(journal_device);
+ } else if ((journal_size) ||
+ (fs_param.s_feature_compat &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
+ if (super_only) {
+ printf("%s", _("Skipping journal creation in super-only mode\n"));
+ fs->super->s_journal_inum = EXT2_JOURNAL_INO;
+ goto no_journal;
+ }
+
+ if (!journal_blocks) {
+ fs->super->s_feature_compat &=
+ ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ goto no_journal;
+ }
+ if (!quiet) {
+ printf(_("Creating journal (%u blocks): "),
+ journal_blocks);
+ fflush(stdout);
+ }
+ retval = ext2fs_add_journal_inode(fs, journal_blocks,
+ journal_flags);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("\n\twhile trying to create journal"));
+ exit(1);
+ }
+ if (!quiet)
+ printf("%s", _("done\n"));
+ }
+no_journal:
+ if (!super_only &&
+ fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) {
+ retval = ext2fs_mmp_init(fs);
+ if (retval) {
+ fprintf(stderr, "%s",
+ _("\nError while enabling multiple "
+ "mount protection feature."));
+ exit(1);
+ }
+ if (!quiet)
+ printf(_("Multiple mount protection is enabled "
+ "with update interval %d seconds.\n"),
+ fs->super->s_mmp_update_interval);
+ }
+
+ if (EXT2_HAS_RO_COMPAT_FEATURE(&fs_param,
+ EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+ fix_cluster_bg_counts(fs);
+ if (EXT2_HAS_RO_COMPAT_FEATURE(&fs_param,
+ EXT4_FEATURE_RO_COMPAT_QUOTA))
+ create_quota_inodes(fs);
+
+ if (!quiet)
+ printf("%s", _("Writing superblocks and "
+ "filesystem accounting information: "));
+ checkinterval = fs->super->s_checkinterval;
+ max_mnt_count = fs->super->s_max_mnt_count;
+ retval = ext2fs_close(fs);
+ if (retval) {
+ fprintf(stderr, "%s",
+ _("\nWarning, had trouble writing out superblocks."));
+ } else if (!quiet) {
+ printf("%s", _("done\n\n"));
+ if (!getenv("MKE2FS_SKIP_CHECK_MSG"))
+ print_check_message(max_mnt_count, checkinterval);
+ }
+
+ remove_error_table(&et_ext2_error_table);
+ remove_error_table(&et_prof_error_table);
+ profile_release(profile);
+ for (i=0; fs_types[i]; i++)
+ free(fs_types[i]);
+ free(fs_types);
+ return retval;
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.conf.5.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.conf.5.in
new file mode 100644
index 0000000..0625d0e
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.conf.5.in
@@ -0,0 +1,431 @@
+.\" -*- nroff -*-
+.\" Copyright 2006 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH mke2fs.conf 5 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+mke2fs.conf \- Configuration file for mke2fs
+.SH DESCRIPTION
+.I mke2fs.conf
+is the configuration file for
+.BR mke2fs (8).
+It controls the default parameters used by
+.BR mke2fs (8)
+when it is creating ext2, ext3, or ext4 filesystems.
+.PP
+The
+.I mke2fs.conf
+file uses an INI-style format. Stanzas, or top-level sections, are
+delimited by square braces: [ ]. Within each section, each line
+defines a relation, which assigns tags to values, or to a subsection,
+which contains further relations or subsections.
+.\" Tags can be assigned multiple values
+An example of the INI-style format used by this configuration file
+follows below:
+.P
+ [section1]
+.br
+ tag1 = value_a
+.br
+ tag1 = value_b
+.br
+ tag2 = value_c
+.P
+ [section 2]
+.br
+ tag3 = {
+.br
+ subtag1 = subtag_value_a
+.br
+ subtag1 = subtag_value_b
+.br
+ subtag2 = subtag_value_c
+.br
+ }
+.br
+ tag1 = value_d
+.br
+ tag2 = value_e
+.br
+ }
+.P
+Comments are delimited by a semicolon (';') or a hash ('#') character
+at the beginning of the comment, and are terminated by the end of
+line character.
+.P
+Tags and values must be quoted using double quotes if they contain
+spaces. Within a quoted string, the standard backslash interpretations
+apply: "\en" (for the newline character),
+"\et" (for the tab character), "\eb" (for the backspace character),
+and "\e\e" (for the backslash character).
+.P
+Some relations expect a boolean value. The parser is quite liberal on
+recognizing ``yes'', '`y'', ``true'', ``t'', ``1'', ``on'', etc. as a
+boolean true value, and ``no'', ``n'', ``false'', ``nil'', ``0'',
+``off'' as a boolean false value.
+.P
+The following stanzas are used in the
+.I mke2fs.conf
+file. They will be described in more detail in future sections of this
+document.
+.TP
+.I [defaults]
+Contains relations which define the default parameters
+used by
+.BR mke2fs (8).
+In general, these defaults may be overridden by a definition in the
+.B fs_types
+stanza, or by an command-line option provided by the user.
+.TP
+.I [fs_types]
+Contains relations which define defaults that should be used for specific
+filesystem types. The filesystem type can be specified explicitly using
+the
+.B -T
+option to
+.BR mke2fs (8).
+.SH THE [defaults] STANZA
+The following relations are defined in the
+.I [defaults]
+stanza.
+.TP
+.I base_features
+This relation specifies the filesystems features which are enabled in
+newly created filesystems. It may be overridden by the
+.I base_features
+relation found in the filesystem or usage type subsection of
+the
+.I [fs_types]
+stanza.
+.TP
+.I default_features
+This relation specifies a set of features that should be added or
+removed to the features listed in the
+.I base_features
+relation. It may be overridden by the filesystem-specific
+.I default_features
+in the filesystem or usage type subsection of
+.IR [fs_types] ,
+and by the
+.B -O
+command-line option
+to
+.BR mke2fs (8).
+.TP
+.I enable_periodic_fsck
+This boolean relation specifies whether periodic filesystem checks should be
+enforced at boot time. If set to true, checks will be forced every
+180 days, or after a random number of mounts. These values may
+be changed later via the
+.B -i
+and
+.B -c
+command-line options to
+.BR tune2fs (8).
+.TP
+.I force_undo
+This boolean relation, if set to a value of true, forces
+.B mke2fs
+to always try to create an undo file, even if the undo file might be
+huge and it might extend the time to create the filesystem image
+because the inode table isn't being initialized lazily.
+.TP
+.I fs_type
+This relation specifies the default filesystem type if the user does not
+specify it via the
+.B \-t
+option, or if
+.B mke2fs
+is not started using a program name of the form
+.BI mkfs. fs-type\fR.
+If both the user and the
+.B mke2fs.conf
+file does not specify a default filesystem type, mke2fs will use a
+default filesystem type of
+.IR ext3
+if a journal was requested via a command-line option, or
+.I ext2
+if not.
+.TP
+.I blocksize
+This relation specifies the default blocksize if the user does not
+specify a blocksize on the command line, and the filesystem-type
+specific section of the configuration file does not specify a blocksize.
+.TP
+.I hash_alg
+This relation specifies the default hash algorithm used for the
+new filesystems with hashed b-tree directories. Valid algorithms
+accepted are:
+.IR legacy ,
+.IR half_md4 ,
+and
+.IR tea .
+.TP
+.I inode_ratio
+This relation specifies the default inode ratio if the user does not
+specify one on the command line, and the filesystem-type
+specific section of the configuration file does not specify a default
+inode ratio.
+.TP
+.I inode_size
+This relation specifies the default inode size if the user does not
+specify one on the command line, and the filesystem-type
+specific section of the configuration file does not specify a default
+inode size.
+.TP
+.I reserved_ratio
+This relation specifies the default percentage of filesystem blocks
+reserved for the super-user, if the user does not
+specify one on the command line, and the filesystem-type
+specific section of the configuration file does not specify a default
+reserved ratio. This value can be a floating point number.
+.TP
+.I undo_dir
+This relation specifies the directory where the undo file should be
+stored. It can be overridden via the
+.B E2FSPROGS_UNDO_DIR
+environment variable. If the directory location is set to the value
+.IR none ,
+.B mke2fs
+will not create an undo file.
+.SH THE [fs_types] STANZA
+Each tag in the
+.I [fs_types]
+stanza names a filesystem type or usage type which can be specified via the
+.B \-t
+or
+.B \-T
+options to
+.BR mke2fs (8),
+respectively.
+.P
+The
+.B mke2fs
+program constructs a list of fs_types by concatenating the filesystem
+type (i.e., ext2, ext3, etc.) with the usage type list. For most
+configuration options,
+.B mke2fs
+will look for a subsection in the
+.I [fs_types]
+stanza corresponding with each entry in the constructed list, with later
+entries overriding earlier filesystem or usage types.
+For
+example, consider the following
+.B mke2fs.conf
+fragment:
+.P
+[defaults]
+.br
+ base_features = sparse_super,filetype,resize_inode,dir_index
+.br
+ blocksize = 4096
+.br
+ inode_size = 256
+.br
+ inode_ratio = 16384
+.br
+
+.br
+[fs_types]
+.br
+ ext3 = {
+.br
+ features = has_journal
+.br
+ }
+.br
+ ext4 = {
+.br
+ features = extents,flex_bg
+.br
+ inode_size = 256
+.br
+ }
+.br
+ small = {
+.br
+ blocksize = 1024
+.br
+ inode_ratio = 4096
+.br
+ }
+.br
+ floppy = {
+.br
+ features = ^resize_inode
+.br
+ blocksize = 1024
+.br
+ inode_size = 128
+.br
+ }
+.P
+If mke2fs started with a program name of
+.BR mke2fs.ext4 ,
+then the filesystem type of ext4 will be used. If the filesystem is
+smaller than 3 megabytes, and no usage type is specified, then
+.B mke2fs
+will use a default
+usage type of
+.IR floppy .
+This results in an fs_types list of "ext4, floppy". Both the ext4
+subsection and the floppy subsection define an
+.I inode_size
+relation, but since the later entries in the fs_types list supersede
+earlier ones, the configuration parameter for fs_types.floppy.inode_size
+will be used, so the filesystem will have an inode size of 128.
+.P
+The exception to this resolution is the
+.I features
+tag, which is specifies a set of changes to the features used by the
+filesystem, and which is cumulative. So in the above example, first
+the configuration relation defaults.base_features would enable an
+initial feature set with the sparse_super, filetype, resize_inode, and
+dir_index features enabled. Then configuration relation
+fs_types.ext4.features would enable the extents and flex_bg
+features, and finally the configuration relation
+fs_types.floppy.features would remove
+the resize_inode feature, resulting in a filesystem feature set
+consisting of the sparse_super, filetype, resize_inode, dir_index,
+extents_and flex_bg features.
+.P
+For each filesystem type, the following tags may be used in that
+fs_type's subsection:
+.TP
+.I base_features
+This relation specifies the features which are initially enabled for this
+filesystem type. Only one
+.I base_features
+will be used, so if there are multiple entries in the fs_types list
+whose subsections define the
+.I base_features
+relation, only the last will be used by
+.BR mke2fs (8).
+.TP
+.I features
+This relation specifies a comma-separated list of features edit
+requests which modify the feature set
+used by the newly constructed filesystem. The syntax is the same as the
+.B -O
+command-line option to
+.BR mke2fs (8);
+that is, a feature can be prefixed by a caret ('^') symbol to disable
+a named feature. Each
+.I feature
+relation specified in the fs_types list will be applied in the order
+found in the fs_types list.
+.TP
+.I default_features
+This relation specifies set of features which should be enabled or
+disabled after applying the features listed in the
+.I base_features
+and
+.I features
+relations. It may be overridden by the
+.B -O
+command-line option to
+.BR mke2fs (8).
+.TP
+.I auto_64-bit_support
+This relation is a boolean which specifies whether
+.BR mke2fs (8)
+should automatically add the 64bit feature if the number of blocks for
+the file system requires this feature to be enabled. The resize_inode
+feature is also automatically disabled since it doesn't support 64-bit
+block numbers.
+.TP
+.I default_mntopts
+This relation specifies the set of mount options which should be enabled
+by default. These may be changed at a later time with the
+.B -o
+command-line option to
+.BR tune2fs (8).
+.TP
+.I blocksize
+This relation specifies the default blocksize if the user does not
+specify a blocksize on the command line.
+.TP
+.I lazy_itable_init
+This boolean relation specifies whether the inode table should
+be lazily initialized. It only has meaning if the uninit_bg feature is
+enabled. If lazy_itable_init is true and the uninit_bg feature is
+enabled, the inode table will
+not fully initialized by
+.BR mke2fs (8).
+This speeds up filesystem
+initialization noticeably, but it requires the kernel to finish
+initializing the filesystem in the background when the filesystem is
+first mounted.
+.TP
+.I inode_ratio
+This relation specifies the default inode ratio if the user does not
+specify one on the command line.
+.TP
+.I inode_size
+This relation specifies the default inode size if the user does not
+specify one on the command line.
+.TP
+.I reserved_ratio
+This relation specifies the default percentage of filesystem blocks
+reserved for the super-user, if the user does not specify one on the command
+line.
+.TP
+.I hash_alg
+This relation specifies the default hash algorithm used for the
+new filesystems with hashed b-tree directories. Valid algorithms
+accepted are:
+.IR legacy ,
+.IR half_md4 ,
+and
+.IR tea .
+.TP
+.I flex_bg_size
+This relation specifies the number of block groups that will be packed
+together to create one large virtual block group on an ext4 filesystem.
+This improves meta-data locality and performance on meta-data heavy
+workloads. The number of groups must be a power of 2 and may only be
+specified if the flex_bg filesystem feature is enabled.
+.TP
+.I options
+This relation specifies additional extended options which should be
+treated by
+.BR mke2fs (8)
+as if they were prepended to the argument of the
+.B -E
+option. This can be used to configure the default extended options used
+by
+.BR mke2fs (8)
+on a per-filesystem type basis.
+.TP
+.I discard
+This boolean relation specifies whether the
+.BR mke2fs (8)
+should attempt to discard device prior to filesystem creation.
+.TP
+.I cluster_size
+This relation specifies the default cluster size if the bigalloc file
+system feature is enabled. It can be overridden via the
+.B \-C
+command line option to
+.BR mke2fs (8)
+.SH THE [devices] STANZA
+Each tag in the
+.I [devices]
+stanza names device name so that per-device defaults can be specified.
+.TP
+.I fs_type
+This relation specifies the default parameter for the
+.B \-t
+option, if this option isn't specified on the command line.
+.TP
+.I usage_types
+This relation specifies the default parameter for the
+.B \-T
+option, if this option isn't specified on the command line.
+.SH FILES
+.TP
+.I /etc/mke2fs.conf
+The configuration file for
+.BR mke2fs (8).
+.SH SEE ALSO
+.BR mke2fs (8)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.conf.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.conf.in
new file mode 100644
index 0000000..0871f77
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mke2fs.conf.in
@@ -0,0 +1,53 @@
+[defaults]
+ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr
+ default_mntopts = acl,user_xattr
+ enable_periodic_fsck = 0
+ blocksize = 4096
+ inode_size = 256
+ inode_ratio = 16384
+
+[fs_types]
+ ext3 = {
+ features = has_journal
+ }
+ ext4 = {
+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize
+ auto_64-bit_support = 1
+ inode_size = 256
+ }
+ ext4dev = {
+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize
+ inode_size = 256
+ options = test_fs=1
+ }
+ small = {
+ blocksize = 1024
+ inode_size = 128
+ inode_ratio = 4096
+ }
+ floppy = {
+ blocksize = 1024
+ inode_size = 128
+ inode_ratio = 8192
+ }
+ big = {
+ inode_ratio = 32768
+ }
+ huge = {
+ inode_ratio = 65536
+ }
+ news = {
+ inode_ratio = 4096
+ }
+ largefile = {
+ inode_ratio = 1048576
+ blocksize = -1
+ }
+ largefile4 = {
+ inode_ratio = 4194304
+ blocksize = -1
+ }
+ hurd = {
+ blocksize = 4096
+ inode_size = 128
+ }
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mklost+found.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mklost+found.8.in
new file mode 100644
index 0000000..712740c
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mklost+found.8.in
@@ -0,0 +1,43 @@
+.\" -*- nroff -*-
+.\" Copyright 1993, 1994, 1995 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH MKLOST+FOUND 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+mklost+found \- create a lost+found directory on a mounted Linux
+second extended file system
+.SH SYNOPSIS
+.B mklost+found
+.SH DESCRIPTION
+.B mklost+found
+is used to create a
+.I lost+found
+directory in the current working directory on a Linux second extended
+file system. There is normally a
+.I lost+found
+directory in the root directory of each filesystem.
+.PP
+.B mklost+found
+pre-allocates disk blocks to the
+.I lost+found
+directory so that when
+.BR e2fsck (8)
+is being run to recover a filesystem, it does not need to allocate blocks in
+the filesystem to store a large number of unlinked files. This ensures that
+.B e2fsck
+will not have to allocate data blocks in the filesystem during recovery.
+.SH OPTIONS
+There are none.
+.SH AUTHOR
+.B mklost+found
+has been written by Remy Card <Remy.Card@linux.org>. It is currently being
+maintained by Theodore Ts'o <tytso@alum.mit.edu>.
+.SH BUGS
+There are none :-)
+.SH AVAILABILITY
+.B mklost+found
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR e2fsck (8),
+.BR mke2fs (8)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mklost+found.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mklost+found.c
new file mode 100644
index 0000000..134e824
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/mklost+found.c
@@ -0,0 +1,87 @@
+/*
+ * mklost+found.c - Creates a directory lost+found on a mounted second
+ * extended file system
+ *
+ * Copyright (C) 1992, 1993 Remy Card <card@masi.ibp.fr>
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/04/22 - Creation
+ */
+
+#include "config.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include "ext2fs/ext2_fs.h"
+#include "../version.h"
+#include "nls-enable.h"
+
+#define LPF "lost+found"
+
+int main (int argc, char ** argv)
+{
+ char name [EXT2_NAME_LEN];
+ char path [sizeof (LPF) + 1 + 256];
+ struct stat st;
+ int i, j;
+ int d;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+#endif
+ fprintf (stderr, "mklost+found %s (%s)\n", E2FSPROGS_VERSION,
+ E2FSPROGS_DATE);
+ if (argc != 1) {
+ (void)argv; /* avoid unused argument warning */
+ fprintf (stderr, "%s", _("Usage: mklost+found\n"));
+ exit(1);
+ }
+ if (mkdir (LPF, 0700) == -1) {
+ perror ("mkdir");
+ exit(1);
+ }
+
+ i = 0;
+ memset (name, 'x', 246);
+ do {
+ sprintf (name + 246, "%08d", i);
+ strcpy (path, LPF);
+ strcat (path, "/");
+ strcat (path, name);
+ if ((d = creat (path, 0644)) == -1) {
+ perror ("creat");
+ exit (1);
+ }
+ i++;
+ close (d);
+ if (stat (LPF, &st) == -1) {
+ perror ("stat");
+ exit (1);
+ }
+ } while (st.st_size <= (EXT2_NDIR_BLOCKS - 1) * st.st_blksize);
+ for (j = 0; j < i; j++) {
+ sprintf (name + 246, "%08d", j);
+ strcpy (path, LPF);
+ strcat (path, "/");
+ strcat (path, name);
+ if (unlink (path) == -1) {
+ perror ("unlink");
+ exit (1);
+ }
+ }
+ exit (0);
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/nls-enable.h b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/nls-enable.h
new file mode 100644
index 0000000..a91dcc1
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/nls-enable.h
@@ -0,0 +1,21 @@
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#include <locale.h>
+#define _(a) (gettext (a))
+#ifdef gettext_noop
+#define N_(a) gettext_noop (a)
+#else
+#define N_(a) (a)
+#endif
+#define P_(singular, plural, n) (ngettext (singular, plural, n))
+#ifndef NLS_CAT_NAME
+#define NLS_CAT_NAME "e2fsprogs"
+#endif
+#ifndef LOCALEDIR
+#define LOCALEDIR "/usr/share/locale"
+#endif
+#else
+#define _(a) (a)
+#define N_(a) a
+#define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
+#endif
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/partinfo.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/partinfo.c
new file mode 100644
index 0000000..c461e80
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/partinfo.c
@@ -0,0 +1,78 @@
+/*
+ * partinfo.c
+ *
+ * Originally written by Alain Knaff, <alknaff@innet.lu>.
+ *
+ * Cleaned up by Theodore Ts'o, <tytso@mit.edu>.
+ *
+ */
+
+#include "config.h"
+#include <sys/types.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <stdio.h>
+#include <linux/hdreg.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "nls-enable.h"
+
+#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#endif
+
+int main(int argc, char **argv)
+{
+ struct hd_geometry loc;
+ int fd, i;
+ unsigned long size;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+ if (argc == 1) {
+ fprintf(stderr, _("Usage: %s device...\n\nPrints out the "
+ "partition information for each given device.\n"
+ "For example: %s /dev/hda\n\n"), argv[0], argv[0]);
+ exit(1);
+ }
+
+ for (i=1; i < argc; i++) {
+ fd = open(argv[i], O_RDONLY);
+
+ if (fd < 0) {
+ fprintf(stderr, _("Cannot open %s: %s"),
+ argv[i], strerror(errno));
+ continue;
+ }
+
+ if (ioctl(fd, HDIO_GETGEO, &loc) < 0) {
+ fprintf(stderr, _("Cannot get geometry of %s: %s"),
+ argv[i], strerror(errno));
+ close(fd);
+ continue;
+ }
+
+
+ if (ioctl(fd, BLKGETSIZE, &size) < 0) {
+ fprintf(stderr, _("Cannot get size of %s: %s"),
+ argv[i], strerror(errno));
+ close(fd);
+ continue;
+ }
+
+ printf(_("%s: h=%3d s=%3d c=%4d start=%8d size=%8lu end=%8d\n"),
+ argv[i],
+ loc.heads, (int)loc.sectors, loc.cylinders,
+ (int)loc.start, size, (int) loc.start + size -1);
+ close(fd);
+ }
+ exit(0);
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/profile-to-c.awk b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/profile-to-c.awk
new file mode 100644
index 0000000..f964efd
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/profile-to-c.awk
@@ -0,0 +1,12 @@
+#!/bin/awk
+BEGIN {
+ printf("const char *mke2fs_default_profile = \n");
+}
+
+{
+ printf(" \"%s\\n\"\n", $0);
+}
+
+END {
+ printf(";\n", str)
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/tune2fs.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/tune2fs.8.in
new file mode 100644
index 0000000..da21080
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/tune2fs.8.in
@@ -0,0 +1,696 @@
+.\" Revision 1.0 93/06/3 23:00 chk
+.\" Initial revision
+.\"
+.\"
+.TH TUNE2FS 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+tune2fs \- adjust tunable filesystem parameters on ext2/ext3/ext4 filesystems
+.SH SYNOPSIS
+.B tune2fs
+[
+.B \-l
+]
+[
+.B \-c
+.I max-mount-counts
+]
+[
+.B \-e
+.I errors-behavior
+]
+[
+.B \-f
+]
+[
+.B \-i
+.I interval-between-checks
+]
+[
+.B \-j
+]
+[
+.B \-J
+.I journal-options
+]
+[
+.B \-m
+.I reserved-blocks-percentage
+]
+[
+.B \-o
+.RI [^]mount-options [,...]
+]
+[
+.B \-r
+.I reserved-blocks-count
+]
+[
+.B \-s
+.I sparse-super-flag
+]
+[
+.B \-u
+.I user
+]
+[
+.B \-g
+.I group
+]
+[
+.B \-C
+.I mount-count
+]
+[
+.B \-E
+.I extended-options
+]
+[
+.B \-L
+.I volume-name
+]
+[
+.B \-M
+.I last-mounted-directory
+]
+[
+.B \-O
+.RI [^] feature [,...]
+]
+[
+.B \-Q
+.I quota-options
+]
+[
+.B \-T
+.I time-last-checked
+]
+[
+.B \-U
+.I UUID
+]
+device
+.SH DESCRIPTION
+.BI tune2fs
+allows the system administrator to adjust various tunable filesystem
+parameters on Linux ext2, ext3, or ext4 filesystems. The current values
+of these options can be displayed by using the
+.B -l
+option to
+.BR tune2fs (8)
+program, or by using the
+.BR dumpe2fs (8)
+program.
+.PP
+The
+.I device
+specifier can either be a filename (i.e., /dev/sda1), or a LABEL or UUID
+specifier: "\fBLABEL=\fIvolume-name\fR" or "\fBUUID=\fIuuid\fR". (i.e.,
+LABEL=home or UUID=e40486c6-84d5-4f2f-b99c-032281799c9d).
+.SH OPTIONS
+.TP
+.BI \-c " max-mount-counts"
+Adjust the number of mounts after which the filesystem will be checked by
+.BR e2fsck (8).
+If
+.I max-mount-counts
+is 0 or \-1, the number of times the filesystem is mounted will be disregarded
+by
+.BR e2fsck (8)
+and the kernel.
+.sp
+Staggering the mount-counts at which filesystems are forcibly
+checked will avoid all filesystems being checked at one time
+when using journaled filesystems.
+.sp
+You should strongly consider the consequences of disabling
+mount-count-dependent checking entirely. Bad disk drives, cables,
+memory, and kernel bugs could all corrupt a filesystem without
+marking the filesystem dirty or in error. If you are using
+journaling on your filesystem, your filesystem will
+.B never
+be marked dirty, so it will not normally be checked. A
+filesystem error detected by the kernel will still force
+an fsck on the next reboot, but it may already be too late
+to prevent data loss at that point.
+.sp
+See also the
+.B \-i
+option for time-dependent checking.
+.TP
+.BI \-C " mount-count"
+Set the number of times the filesystem has been mounted.
+If set to a greater value than the max-mount-counts parameter
+set by the
+.B \-c
+option,
+.BR e2fsck (8)
+will check the filesystem at the next reboot.
+.TP
+.BI \-e " error-behavior"
+Change the behavior of the kernel code when errors are detected.
+In all cases, a filesystem error will cause
+.BR e2fsck (8)
+to check the filesystem on the next boot.
+.I error-behavior
+can be one of the following:
+.RS 1.2i
+.TP 1.2i
+.B continue
+Continue normal execution.
+.TP
+.B remount-ro
+Remount filesystem read-only.
+.TP
+.B panic
+Cause a kernel panic.
+.RE
+.TP
+.BI \-E " extended-options"
+Set extended options for the filesystem. Extended options are comma
+separated, and may take an argument using the equals ('=') sign.
+The following extended options are supported:
+.RS 1.2i
+.TP
+.B clear_mmp
+Reset the MMP block (if any) back to the clean state. Use only if
+absolutely certain the device is not currently mounted or being
+fscked, or major filesystem corruption can result. Needs '-f'.
+.TP
+.BI mmp_update_interval= interval
+Adjust the initial MMP update interval to
+.I interval
+seconds. Specifying an
+.I interval
+of 0 means to use the default interval. The specified interval must
+be less than 300 seconds. Requires that the
+.B mmp
+feature be enabled.
+.TP
+.BI stride= stride-size
+Configure the filesystem for a RAID array with
+.I stride-size
+filesystem blocks. This is the number of blocks read or written to disk
+before moving to next disk. This mostly affects placement of filesystem
+metadata like bitmaps at
+.BR mke2fs (2)
+time to avoid placing them on a single disk, which can hurt the performance.
+It may also be used by block allocator.
+.TP
+.BI stripe_width= stripe-width
+Configure the filesystem for a RAID array with
+.I stripe-width
+filesystem blocks per stripe. This is typically be stride-size * N, where
+N is the number of data disks in the RAID (e.g. RAID 5 N+1, RAID 6 N+2).
+This allows the block allocator to prevent read-modify-write of the
+parity in a RAID stripe if possible when the data is written.
+.TP
+.BI hash_alg= hash-alg
+Set the default hash algorithm used for filesystems with hashed b-tree
+directories. Valid algorithms accepted are:
+.IR legacy ,
+.IR half_md4 ,
+and
+.IR tea .
+.TP
+.BI mount_opts= mount_option_string
+Set a set of default mount options which will be used when the file
+system is mounted. Unlike the bitmask-based default mount options which
+can be specified with the
+.B -o
+option,
+.I mount_option_string
+is an arbitrary string with a maximum length of 63 bytes, which is
+stored in the superblock.
+.IP
+The ext4 file system driver will first apply
+the bitmask-based default options, and then parse the
+.IR mount_option_string ,
+before parsing the mount options passed from the
+.BR mount (8)
+program.
+.IP
+This superblock setting is only honored in 2.6.35+ kernels;
+and not at all by the ext2 and ext3 file system drivers.
+.TP
+.B test_fs
+Set a flag in the filesystem superblock indicating that it may be
+mounted using experimental kernel code, such as the ext4dev filesystem.
+.TP
+.B ^test_fs
+Clear the test_fs flag, indicating the filesystem should only be mounted
+using production-level filesystem code.
+.RE
+.TP
+.B \-f
+Force the tune2fs operation to complete even in the face of errors. This
+option is useful when removing the
+.B has_journal
+filesystem feature from a filesystem which has
+an external journal (or is corrupted
+such that it appears to have an external journal), but that
+external journal is not available.
+.sp
+.B WARNING:
+Removing an external journal from a filesystem which was not cleanly unmounted
+without first replaying the external journal can result in
+severe data loss and filesystem corruption.
+.TP
+.BI \-g " group"
+Set the group which can use the reserved filesystem blocks.
+The
+.I group
+parameter can be a numerical gid or a group name. If a group name is given,
+it is converted to a numerical gid before it is stored in the superblock.
+.TP
+.B \-i " \fIinterval-between-checks\fR[\fBd\fR|\fBm\fR|\fBw\fR]"
+Adjust the maximal time between two filesystem checks.
+No suffix or
+.B d
+will interpret the number
+.I interval-between-checks
+as days,
+.B m
+as months, and
+.B w
+as weeks. A value of zero will disable the time-dependent checking.
+.sp
+It is strongly recommended that either
+.B \-c
+(mount-count-dependent) or
+.B \-i
+(time-dependent) checking be enabled to force periodic full
+.BR e2fsck (8)
+checking of the filesystem. Failure to do so may lead to filesystem
+corruption (due to bad disks, cables, memory, or kernel bugs) going
+unnoticed, ultimately resulting in data loss or corruption.
+.TP
+.B \-j
+Add an ext3 journal to the filesystem. If the
+.B \-J
+option is not specified, the default journal parameters will be used to create
+an appropriately sized journal (given the size of the filesystem)
+stored within the filesystem. Note that you must be using a kernel
+which has ext3 support in order to actually make use of the journal.
+.IP
+If this option is used to create a journal on a mounted filesystem, an
+immutable file,
+.BR .journal ,
+will be created in the top-level directory of the filesystem, as it is
+the only safe way to create the journal inode while the filesystem is
+mounted. While the ext3 journal is visible, it is not safe to
+delete it, or modify it while the filesystem is mounted; for this
+reason the file is marked immutable.
+While checking unmounted filesystems,
+.BR e2fsck (8)
+will automatically move
+.B .journal
+files to the invisible, reserved journal inode. For all filesystems
+except for the root filesystem, this should happen automatically and
+naturally during the next reboot cycle. Since the root filesystem is
+mounted read-only,
+.BR e2fsck (8)
+must be run from a rescue floppy in order to effect this transition.
+.IP
+On some distributions, such as Debian, if an initial ramdisk is used,
+the initrd scripts will automatically convert an ext2 root filesystem
+to ext3 if the
+.BR /etc/fstab
+file specifies the ext3 filesystem for the root filesystem in order to
+avoid requiring the use of a rescue floppy to add an ext3 journal to
+the root filesystem.
+.TP
+.BR \-J " journal-options"
+Override the default ext3 journal parameters. Journal options are comma
+separated, and may take an argument using the equals ('=') sign.
+The following journal options are supported:
+.RS 1.2i
+.TP
+.BI size= journal-size
+Create a journal stored in the filesystem of size
+.I journal-size
+megabytes. The size of the journal must be at least 1024 filesystem blocks
+(i.e., 1MB if using 1k blocks, 4MB if using 4k blocks, etc.)
+and may be no more than 102,400 filesystem blocks.
+There must be enough free space in the filesystem to create a journal of
+that size.
+@JDEV@.TP
+@JDEV@.BI device= external-journal
+@JDEV@Attach the filesystem to the journal block device located on
+@JDEV@.IR external-journal .
+@JDEV@The external
+@JDEV@journal must have been already created using the command
+@JDEV@.IP
+@JDEV@.B mke2fs -O journal_dev
+@JDEV@.I external-journal
+@JDEV@.IP
+@JDEV@Note that
+@JDEV@.I external-journal
+@JDEV@must be formatted with the same block
+@JDEV@size as filesystems which will be using it.
+@JDEV@In addition, while there is support for attaching
+@JDEV@multiple filesystems to a single external journal,
+@JDEV@the Linux kernel and
+@JDEV@.BR e2fsck (8)
+@JDEV@do not currently support shared external journals yet.
+@JDEV@.IP
+@JDEV@Instead of specifying a device name directly,
+@JDEV@.I external-journal
+@JDEV@can also be specified by either
+@JDEV@.BI LABEL= label
+@JDEV@or
+@JDEV@.BI UUID= UUID
+@JDEV@to locate the external journal by either the volume label or UUID
+@JDEV@stored in the ext2 superblock at the start of the journal. Use
+@JDEV@.BR dumpe2fs (8)
+@JDEV@to display a journal device's volume label and UUID. See also the
+@JDEV@.B -L
+@JDEV@option of
+@JDEV@.BR tune2fs (8).
+.RE
+@JDEV@.IP
+@JDEV@Only one of the
+@JDEV@.BR size " or " device
+@JDEV@options can be given for a filesystem.
+.TP
+.B \-l
+List the contents of the filesystem superblock, including the current
+values of the parameters that can be set via this program.
+.TP
+.BI \-L " volume-label"
+Set the volume label of the filesystem.
+Ext2 filesystem labels can be at most 16 characters long; if
+.I volume-label
+is longer than 16 characters,
+.B tune2fs
+will truncate it and print a warning. The volume label can be used
+by
+.BR mount (8),
+.BR fsck (8),
+and
+.BR /etc/fstab (5)
+(and possibly others) by specifying
+.BI LABEL= volume_label
+instead of a block special device name like
+.BR /dev/hda5 .
+.TP
+.BI \-m " reserved-blocks-percentage"
+Set the percentage of the filesystem which may only be allocated
+by privileged processes. Reserving some number of filesystem blocks
+for use by privileged processes is done
+to avoid filesystem fragmentation, and to allow system
+daemons, such as
+.BR syslogd (8),
+to continue to function correctly after non-privileged processes are
+prevented from writing to the filesystem. Normally, the default percentage
+of reserved blocks is 5%.
+.TP
+.BI \-M " last-mounted-directory"
+Set the last-mounted directory for the filesystem.
+.TP
+.BR \-o " [^]\fImount-option\fR[,...]"
+Set or clear the indicated default mount options in the filesystem.
+Default mount options can be overridden by mount options specified
+either in
+.BR /etc/fstab (5)
+or on the command line arguments to
+.BR mount (8).
+Older kernels may not support this feature; in particular,
+kernels which predate 2.4.20 will almost certainly ignore the
+default mount options field in the superblock.
+.IP
+More than one mount option can be cleared or set by separating
+features with commas. Mount options prefixed with a
+caret character ('^') will be cleared in the filesystem's superblock;
+mount options without a prefix character or prefixed with a plus
+character ('+') will be added to the filesystem.
+.IP
+The following mount options can be set or cleared using
+.BR tune2fs :
+.RS 1.2i
+.TP
+.B debug
+Enable debugging code for this filesystem.
+.TP
+.B bsdgroups
+Emulate BSD behavior when creating new files: they will take the group-id
+of the directory in which they were created. The standard System V behavior
+is the default, where newly created files take on the fsgid of the current
+process, unless the directory has the setgid bit set, in which case it takes
+the gid from the parent directory, and also gets the setgid bit set if it is
+a directory itself.
+.TP
+.B user_xattr
+Enable user-specified extended attributes.
+.TP
+.B acl
+Enable Posix Access Control Lists.
+.TP
+.B uid16
+Disables 32-bit UIDs and GIDs. This is for interoperability with
+older kernels which only store and expect 16-bit values.
+.TP
+.B journal_data
+When the filesystem is mounted with journalling enabled, all data
+(not just metadata) is committed into the journal prior to being written
+into the main filesystem.
+.TP
+.B journal_data_ordered
+When the filesystem is mounted with journalling enabled, all data is forced
+directly out to the main file system prior to its metadata being committed
+to the journal.
+.TP
+.B journal_data_writeback
+When the filesystem is mounted with journalling enabled, data may be
+written into the main filesystem after its metadata has been committed
+to the journal. This may increase throughput, however, it may allow old
+data to appear in files after a crash and journal recovery.
+.TP
+.B nobarrier
+The file system will be mounted with barrier operations in the journal
+disabled. (This option is currently only supported by the ext4 file
+system driver in 2.6.35+ kernels.)
+.TP
+.B block_validity
+The file system will be mounted with the block_validity option enabled,
+which causes extra checks to be performed after reading or writing from
+the file system. This prevents corrupted metadata blocks from causing
+file system damage by overwriting parts of the inode table or block
+group descriptors. This comes at the cost of increased memory and CPU
+overhead, so it is enabled only for debugging purposes. (This option is
+currently only supported by the ext4 file system driver in 2.6.35+
+kernels.)
+.TP
+.B discard
+The file system will be mounted with the discard mount option. This will
+cause the file system driver to attempt to use the trim/discard feature
+of some storage devices (such as SSD's and thin-provisioned drives
+available in some enterprise storage arrays) to inform the storage
+device that blocks belonging to deleted files can be reused for other
+purposes. (This option is currently only supported by the ext4 file
+system driver in 2.6.35+ kernels.)
+.TP
+.B nodelalloc
+The file system will be mounted with the nodelalloc mount option. This
+will disable the delayed allocation feature. (This option is currently
+only supported by the ext4 file system driver in 2.6.35+ kernels.)
+.RE
+.TP
+.BR \-O " [^]\fIfeature\fR[,...]"
+Set or clear the indicated filesystem features (options) in the filesystem.
+More than one filesystem feature can be cleared or set by separating
+features with commas. Filesystem features prefixed with a
+caret character ('^') will be cleared in the filesystem's superblock;
+filesystem features without a prefix character or prefixed with a plus
+character ('+') will be added to the filesystem. For a detailed
+description of the file system features, please see the man page
+.BR ext4 (5).
+.IP
+The following filesystem features can be set or cleared using
+.BR tune2fs :
+.RS 1.2i
+.TP
+.B dir_index
+Use hashed b-trees to speed up lookups for large directories.
+.TP
+.B dir_nlink
+Allow more than 65000 subdirectories per directory.
+.TP
+.B extent
+Enable the use of extent trees to store the location of data blocks in inodes.
+.TP
+.B extra_isize
+Enable the extended inode fields used by ext4.
+.TP
+.B filetype
+Store file type information in directory entries.
+.TP
+.B flex_bg
+Allow bitmaps and inode tables for a block group to be placed
+anywhere on the storage media. \fBTune2fs\fR will not reorganize
+the location of the inode tables and allocation bitmaps, as
+.BR mke2fs (8)
+will do when it creates a freshly formatted file system with
+.B flex_bg
+enabled.
+.TP
+.B has_journal
+Use a journal to ensure filesystem consistency even across unclean shutdowns.
+Setting the filesystem feature is equivalent to using the
+.B \-j
+option.
+.TP
+.B huge_file
+Support files larger than 2 terabytes in size.
+.TP
+.B large_file
+Filesystem can contain files that are greater than 2GB.
+.TP
+.B resize_inode
+Reserve space so the block group descriptor table may grow in the
+future.
+.B Tune2fs
+only supports clearing this filesystem feature.
+.TP
+.B mmp
+Enable or disable multiple mount protection (MMP) feature.
+@QUOTA_MAN_COMMENT@.TP
+@QUOTA_MAN_COMMENT@.B quota
+@QUOTA_MAN_COMMENT@Enable internal file system quota inodes.
+.TP
+.B sparse_super
+Limit the number of backup superblocks to save space on large filesystems.
+.TP
+.B uninit_bg
+Allow the kernel to initialize bitmaps and inode tables lazily, and to
+keep a high watermark for the unused inodes in a filesystem, to reduce
+.BR e2fsck (8)
+time. This first e2fsck run after enabling this feature will take the
+full time, but subsequent e2fsck runs will take only a fraction of the
+original time, depending on how full the file system is.
+.RE
+.IP
+After setting or clearing
+.BR sparse_super ,
+.BR uninit_bg ,
+.BR filetype ,
+or
+.B resize_inode
+filesystem features,
+.BR e2fsck (8)
+must be run on the filesystem to return the filesystem to a consistent state.
+.B Tune2fs
+will print a message requesting that the system administrator run
+.BR e2fsck (8)
+if necessary. After setting the
+.B dir_index
+feature,
+.B e2fsck -D
+can be run to convert existing directories to the hashed B-tree format.
+Enabling certain filesystem features may prevent the filesystem from being
+mounted by kernels which do not support those features. In particular, the
+.BR uninit_bg
+and
+.BR flex_bg
+features are only supported by the ext4 filesystem.
+.TP
+.BI \-p " mmp_check_interval"
+Set the desired MMP check interval in seconds. It is 5 seconds by default.
+.TP
+.BI \-r " reserved-blocks-count"
+Set the number of reserved filesystem blocks.
+.TP
+.BI \-Q " quota-options"
+Sets 'quota' feature on the superblock and works on the quota files for the
+given quota type. Quota options could be one or more of the following:
+.RS 1.2i
+.TP
+.BR [^]usrquota
+Sets/clears user quota inode in the superblock.
+.TP
+.BR [^]grpquota
+Sets/clears group quota inode in the superblock.
+.RE
+.TP
+.BI \-T " time-last-checked"
+Set the time the filesystem was last checked using
+.BR e2fsck .
+The time is interpreted using the current (local) timezone.
+This can be useful in scripts which use a Logical Volume Manager to make
+a consistent snapshot of a filesystem, and then check the filesystem
+during off hours to make sure it hasn't been corrupted due to
+hardware problems, etc. If the filesystem was clean, then this option can
+be used to set the last checked time on the original filesystem. The format
+of
+.I time-last-checked
+is the international date format, with an optional time specifier, i.e.
+YYYYMMDD[HH[MM[SS]]]. The keyword
+.B now
+is also accepted, in which case the last checked time will be set to the
+current time.
+.TP
+.BI \-u " user"
+Set the user who can use the reserved filesystem blocks.
+.I user
+can be a numerical uid or a user name. If a user name is given, it
+is converted to a numerical uid before it is stored in the superblock.
+.TP
+.BI \-U " UUID"
+Set the universally unique identifier (UUID) of the filesystem to
+.IR UUID .
+The format of the UUID is a series of hex digits separated by hyphens,
+like this:
+"c1b9d5a2-f162-11cf-9ece-0020afc76f16".
+The
+.I UUID
+parameter may also be one of the following:
+.RS 1.2i
+.TP
+.I clear
+clear the filesystem UUID
+.TP
+.I random
+generate a new randomly-generated UUID
+.TP
+.I time
+generate a new time-based UUID
+.RE
+.IP
+The UUID may be used by
+.BR mount (8),
+.BR fsck (8),
+and
+.BR /etc/fstab (5)
+(and possibly others) by specifying
+.BI UUID= uuid
+instead of a block special device name like
+.BR /dev/hda1 .
+.IP
+See
+.BR uuidgen (8)
+for more information.
+If the system does not have a good random number generator such as
+.I /dev/random
+or
+.IR /dev/urandom ,
+.B tune2fs
+will automatically use a time-based UUID instead of a randomly-generated UUID.
+.SH BUGS
+We haven't found any bugs yet. That doesn't mean there aren't any...
+.SH AUTHOR
+.B tune2fs
+was written by Remy Card <Remy.Card@linux.org>. It is currently being
+maintained by Theodore Ts'o <tytso@alum.mit.edu>.
+.B tune2fs
+uses the ext2fs library written by Theodore Ts'o <tytso@mit.edu>.
+This manual page was written by Christian Kuhtz <chk@data-hh.Hanse.DE>.
+Time-dependent checking was added by Uwe Ohse <uwe@tirka.gun.de>.
+.SH AVAILABILITY
+.B tune2fs
+is part of the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH SEE ALSO
+.BR debugfs (8),
+.BR dumpe2fs (8),
+.BR e2fsck (8),
+.BR mke2fs (8),
+.BR ext4 (5)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/tune2fs.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/tune2fs.c
new file mode 100644
index 0000000..568fb30
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/tune2fs.c
@@ -0,0 +1,2270 @@
+/*
+ * tune2fs.c - Change the file system parameters on an ext2 file system
+ *
+ * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/*
+ * History:
+ * 93/06/01 - Creation
+ * 93/10/31 - Added the -c option to change the maximal mount counts
+ * 93/12/14 - Added -l flag to list contents of superblock
+ * M.J.E. Mol (marcel@duteca.et.tudelft.nl)
+ * F.W. ten Wolde (franky@duteca.et.tudelft.nl)
+ * 93/12/29 - Added the -e option to change errors behavior
+ * 94/02/27 - Ported to use the ext2fs library
+ * 94/03/06 - Added the checks interval from Uwe Ohse (uwe@tirka.gun.de)
+ */
+
+#define _XOPEN_SOURCE 600 /* for inclusion of strptime() */
+#include "config.h"
+#include <fcntl.h>
+#include <grp.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+#include <pwd.h>
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h> /* for strcasecmp() */
+#else
+#define _BSD_SOURCE /* for inclusion of strcasecmp() via <string.h> */
+#endif
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <libgen.h>
+#include <limits.h>
+
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+#include "et/com_err.h"
+#include "uuid/uuid.h"
+#include "e2p/e2p.h"
+#include "jfs_user.h"
+#include "util.h"
+#include "blkid/blkid.h"
+#include "quota/mkquota.h"
+
+#include "../version.h"
+#include "nls-enable.h"
+
+#define QOPT_ENABLE (1)
+#define QOPT_DISABLE (-1)
+
+extern int ask_yn(const char *string, int def);
+
+const char *program_name = "tune2fs";
+char *device_name;
+char *new_label, *new_last_mounted, *new_UUID;
+char *io_options;
+static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
+static int m_flag, M_flag, Q_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
+static int I_flag;
+static int clear_mmp;
+static time_t last_check_time;
+static int print_label;
+static int max_mount_count, mount_count, mount_flags;
+static unsigned long interval;
+static blk64_t reserved_blocks;
+static double reserved_ratio;
+static unsigned long resgid, resuid;
+static unsigned short errors;
+static int open_flag;
+static char *features_cmd;
+static char *mntopts_cmd;
+static int stride, stripe_width;
+static int stride_set, stripe_width_set;
+static char *extended_cmd;
+static unsigned long new_inode_size;
+static char *ext_mount_opts;
+static int usrquota, grpquota;
+
+int journal_size, journal_flags;
+char *journal_device;
+
+static struct list_head blk_move_list;
+
+struct blk_move {
+ struct list_head list;
+ blk64_t old_loc;
+ blk64_t new_loc;
+};
+
+
+static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
+
+#ifdef CONFIG_BUILD_FINDFS
+void do_findfs(int argc, char **argv);
+#endif
+
+static void usage(void)
+{
+ fprintf(stderr,
+ _("Usage: %s [-c max_mounts_count] [-e errors_behavior] "
+ "[-g group]\n"
+ "\t[-i interval[d|m|w]] [-j] [-J journal_options] [-l]\n"
+ "\t[-m reserved_blocks_percent] "
+ "[-o [^]mount_options[,...]] [-p mmp_update_interval]\n"
+ "\t[-r reserved_blocks_count] [-u user] [-C mount_count] "
+ "[-L volume_label]\n"
+ "\t[-M last_mounted_dir] [-O [^]feature[,...]]\n"
+#ifdef CONFIG_QUOTA
+ "\t[-Q quota_options]\n"
+#endif
+ "\t[-E extended-option[,...]] [-T last_check_time] "
+ "[-U UUID]\n\t[ -I new_inode_size ] device\n"), program_name);
+ exit(1);
+}
+
+static __u32 ok_features[3] = {
+ /* Compat */
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL |
+ EXT2_FEATURE_COMPAT_DIR_INDEX,
+ /* Incompat */
+ EXT2_FEATURE_INCOMPAT_FILETYPE |
+ EXT3_FEATURE_INCOMPAT_EXTENTS |
+ EXT4_FEATURE_INCOMPAT_FLEX_BG |
+ EXT4_FEATURE_INCOMPAT_MMP,
+ /* R/O compat */
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
+#ifdef CONFIG_QUOTA
+ EXT4_FEATURE_RO_COMPAT_QUOTA |
+#endif
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+};
+
+static __u32 clear_ok_features[3] = {
+ /* Compat */
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL |
+ EXT2_FEATURE_COMPAT_RESIZE_INODE |
+ EXT2_FEATURE_COMPAT_DIR_INDEX,
+ /* Incompat */
+ EXT2_FEATURE_INCOMPAT_FILETYPE |
+ EXT4_FEATURE_INCOMPAT_FLEX_BG |
+ EXT4_FEATURE_INCOMPAT_MMP,
+ /* R/O compat */
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
+#ifdef CONFIG_QUOTA
+ EXT4_FEATURE_RO_COMPAT_QUOTA |
+#endif
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM
+};
+
+/*
+ * Remove an external journal from the filesystem
+ */
+static int remove_journal_device(ext2_filsys fs)
+{
+ char *journal_path;
+ ext2_filsys jfs;
+ char buf[1024];
+ journal_superblock_t *jsb;
+ int i, nr_users;
+ errcode_t retval;
+ int commit_remove_journal = 0;
+ io_manager io_ptr;
+
+ if (f_flag)
+ commit_remove_journal = 1; /* force removal even if error */
+
+ uuid_unparse(fs->super->s_journal_uuid, buf);
+ journal_path = blkid_get_devname(NULL, "UUID", buf);
+
+ if (!journal_path) {
+ journal_path =
+ ext2fs_find_block_device(fs->super->s_journal_dev);
+ if (!journal_path)
+ goto no_valid_journal;
+ }
+
+#ifdef CONFIG_TESTIO_DEBUG
+ if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
+ io_ptr = test_io_manager;
+ test_io_backing_manager = unix_io_manager;
+ } else
+#endif
+ io_ptr = unix_io_manager;
+ retval = ext2fs_open(journal_path, EXT2_FLAG_RW|
+ EXT2_FLAG_JOURNAL_DEV_OK, 0,
+ fs->blocksize, io_ptr, &jfs);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while trying to open external journal"));
+ goto no_valid_journal;
+ }
+ if (!(jfs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
+ fprintf(stderr, _("%s is not a journal device.\n"),
+ journal_path);
+ goto no_valid_journal;
+ }
+
+ /* Get the journal superblock */
+ if ((retval = io_channel_read_blk64(jfs->io, 1, -1024, buf))) {
+ com_err(program_name, retval, "%s",
+ _("while reading journal superblock"));
+ goto no_valid_journal;
+ }
+
+ jsb = (journal_superblock_t *) buf;
+ if ((jsb->s_header.h_magic != (unsigned)ntohl(JFS_MAGIC_NUMBER)) ||
+ (jsb->s_header.h_blocktype != (unsigned)ntohl(JFS_SUPERBLOCK_V2))) {
+ fputs(_("Journal superblock not found!\n"), stderr);
+ goto no_valid_journal;
+ }
+
+ /* Find the filesystem UUID */
+ nr_users = ntohl(jsb->s_nr_users);
+ for (i = 0; i < nr_users; i++) {
+ if (memcmp(fs->super->s_uuid, &jsb->s_users[i * 16], 16) == 0)
+ break;
+ }
+ if (i >= nr_users) {
+ fputs(_("Filesystem's UUID not found on journal device.\n"),
+ stderr);
+ commit_remove_journal = 1;
+ goto no_valid_journal;
+ }
+ nr_users--;
+ for (i = 0; i < nr_users; i++)
+ memcpy(&jsb->s_users[i * 16], &jsb->s_users[(i + 1) * 16], 16);
+ jsb->s_nr_users = htonl(nr_users);
+
+ /* Write back the journal superblock */
+ if ((retval = io_channel_write_blk64(jfs->io, 1, -1024, buf))) {
+ com_err(program_name, retval,
+ "while writing journal superblock.");
+ goto no_valid_journal;
+ }
+
+ commit_remove_journal = 1;
+
+no_valid_journal:
+ if (commit_remove_journal == 0) {
+ fputs(_("Cannot locate journal device. It was NOT removed\n"
+ "Use -f option to remove missing journal device.\n"),
+ stderr);
+ return 1;
+ }
+ fs->super->s_journal_dev = 0;
+ uuid_clear(fs->super->s_journal_uuid);
+ ext2fs_mark_super_dirty(fs);
+ fputs(_("Journal removed\n"), stdout);
+ free(journal_path);
+
+ return 0;
+}
+
+/* Helper function for remove_journal_inode */
+static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
+ e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
+ blk64_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *private EXT2FS_ATTR((unused)))
+{
+ blk64_t block;
+ int group;
+
+ block = *blocknr;
+ ext2fs_unmark_block_bitmap2(fs->block_map, block);
+ group = ext2fs_group_of_blk2(fs, block);
+ ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) + 1);
+ ext2fs_group_desc_csum_set(fs, group);
+ ext2fs_free_blocks_count_add(fs->super, EXT2FS_CLUSTER_RATIO(fs));
+ return 0;
+}
+
+/*
+ * Remove the journal inode from the filesystem
+ */
+static errcode_t remove_journal_inode(ext2_filsys fs)
+{
+ struct ext2_inode inode;
+ errcode_t retval;
+ ino_t ino = fs->super->s_journal_inum;
+
+ retval = ext2fs_read_inode(fs, ino, &inode);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while reading journal inode"));
+ return retval;
+ }
+ if (ino == EXT2_JOURNAL_INO) {
+ retval = ext2fs_read_bitmaps(fs);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while reading bitmaps"));
+ return retval;
+ }
+ retval = ext2fs_block_iterate3(fs, ino,
+ BLOCK_FLAG_READ_ONLY, NULL,
+ release_blocks_proc, NULL);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while clearing journal inode"));
+ return retval;
+ }
+ memset(&inode, 0, sizeof(inode));
+ ext2fs_mark_bb_dirty(fs);
+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+ } else
+ inode.i_flags &= ~EXT2_IMMUTABLE_FL;
+ retval = ext2fs_write_inode(fs, ino, &inode);
+ if (retval) {
+ com_err(program_name, retval, "%s",
+ _("while writing journal inode"));
+ return retval;
+ }
+ fs->super->s_journal_inum = 0;
+ ext2fs_mark_super_dirty(fs);
+
+ return 0;
+}
+
+/*
+ * Update the default mount options
+ */
+static int update_mntopts(ext2_filsys fs, char *mntopts)
+{
+ struct ext2_super_block *sb = fs->super;
+
+ if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) {
+ fprintf(stderr, _("Invalid mount option set: %s\n"),
+ mntopts);
+ return 1;
+ }
+ ext2fs_mark_super_dirty(fs);
+
+ return 0;
+}
+
+static int check_fsck_needed(ext2_filsys fs)
+{
+ if (fs->super->s_state & EXT2_VALID_FS)
+ return 0;
+ printf("\n%s\n", _(please_fsck));
+ if (mount_flags & EXT2_MF_READONLY)
+ printf(_("(and reboot afterwards!)\n"));
+ return 1;
+}
+
+static void request_fsck_afterwards(ext2_filsys fs)
+{
+ static int requested = 0;
+
+ if (requested++)
+ return;
+ fs->super->s_state &= ~EXT2_VALID_FS;
+ printf("\n%s\n", _(please_fsck));
+ if (mount_flags & EXT2_MF_READONLY)
+ printf("%s", _("(and reboot afterwards!)\n"));
+}
+
+/*
+ * Update the feature set as provided by the user.
+ */
+static int update_feature_set(ext2_filsys fs, char *features)
+{
+ struct ext2_super_block *sb = fs->super;
+ struct ext2_group_desc *gd;
+ __u32 old_features[3];
+ dgrp_t i;
+ int type_err;
+ unsigned int mask_err;
+
+#define FEATURE_ON(type, mask) (!(old_features[(type)] & (mask)) && \
+ ((&sb->s_feature_compat)[(type)] & (mask)))
+#define FEATURE_OFF(type, mask) ((old_features[(type)] & (mask)) && \
+ !((&sb->s_feature_compat)[(type)] & (mask)))
+#define FEATURE_CHANGED(type, mask) ((mask) & \
+ (old_features[(type)] ^ (&sb->s_feature_compat)[(type)]))
+
+ old_features[E2P_FEATURE_COMPAT] = sb->s_feature_compat;
+ old_features[E2P_FEATURE_INCOMPAT] = sb->s_feature_incompat;
+ old_features[E2P_FEATURE_RO_INCOMPAT] = sb->s_feature_ro_compat;
+
+ if (e2p_edit_feature2(features, &sb->s_feature_compat,
+ ok_features, clear_ok_features,
+ &type_err, &mask_err)) {
+ if (!mask_err)
+ fprintf(stderr,
+ _("Invalid filesystem option set: %s\n"),
+ features);
+ else if (type_err & E2P_FEATURE_NEGATE_FLAG)
+ fprintf(stderr, _("Clearing filesystem feature '%s' "
+ "not supported.\n"),
+ e2p_feature2string(type_err &
+ E2P_FEATURE_TYPE_MASK,
+ mask_err));
+ else
+ fprintf(stderr, _("Setting filesystem feature '%s' "
+ "not supported.\n"),
+ e2p_feature2string(type_err, mask_err));
+ return 1;
+ }
+
+ if (FEATURE_OFF(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
+ if ((mount_flags & EXT2_MF_MOUNTED) &&
+ !(mount_flags & EXT2_MF_READONLY)) {
+ fputs(_("The has_journal feature may only be "
+ "cleared when the filesystem is\n"
+ "unmounted or mounted "
+ "read-only.\n"), stderr);
+ return 1;
+ }
+ if (sb->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_RECOVER) {
+ fputs(_("The needs_recovery flag is set. "
+ "Please run e2fsck before clearing\n"
+ "the has_journal flag.\n"), stderr);
+ return 1;
+ }
+ if (sb->s_journal_inum) {
+ if (remove_journal_inode(fs))
+ return 1;
+ }
+ if (sb->s_journal_dev) {
+ if (remove_journal_device(fs))
+ return 1;
+ }
+ }
+ if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP)) {
+ int error;
+
+ if ((mount_flags & EXT2_MF_MOUNTED) ||
+ (mount_flags & EXT2_MF_READONLY)) {
+ fputs(_("The multiple mount protection feature can't\n"
+ "be set if the filesystem is mounted or\n"
+ "read-only.\n"), stderr);
+ return 1;
+ }
+
+ error = ext2fs_mmp_init(fs);
+ if (error) {
+ fputs(_("\nError while enabling multiple mount "
+ "protection feature."), stderr);
+ return 1;
+ }
+
+ /*
+ * We want to update group desc with the new free blocks count
+ */
+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+
+ printf(_("Multiple mount protection has been enabled "
+ "with update interval %ds.\n"),
+ sb->s_mmp_update_interval);
+ }
+
+ if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP)) {
+ int error;
+
+ if (mount_flags & EXT2_MF_READONLY) {
+ fputs(_("The multiple mount protection feature cannot\n"
+ "be disabled if the filesystem is readonly.\n"),
+ stderr);
+ return 1;
+ }
+
+ error = ext2fs_read_bitmaps(fs);
+ if (error) {
+ fputs(_("Error while reading bitmaps\n"), stderr);
+ return 1;
+ }
+
+ error = ext2fs_mmp_read(fs, sb->s_mmp_block, NULL);
+ if (error) {
+ struct mmp_struct *mmp_cmp = fs->mmp_cmp;
+
+ if (error == EXT2_ET_MMP_MAGIC_INVALID)
+ printf(_("Magic number in MMP block does not "
+ "match. expected: %x, actual: %x\n"),
+ EXT4_MMP_MAGIC, mmp_cmp->mmp_magic);
+ else
+ com_err(program_name, error, "%s",
+ _("while reading MMP block."));
+ goto mmp_error;
+ }
+
+ /* We need to force out the group descriptors as well */
+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+ ext2fs_block_alloc_stats2(fs, sb->s_mmp_block, -1);
+mmp_error:
+ sb->s_mmp_block = 0;
+ sb->s_mmp_update_interval = 0;
+ }
+
+ if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
+ /*
+ * If adding a journal flag, let the create journal
+ * code below handle setting the flag and creating the
+ * journal. We supply a default size if necessary.
+ */
+ if (!journal_size)
+ journal_size = -1;
+ sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+ }
+
+ if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX)) {
+ if (!sb->s_def_hash_version)
+ sb->s_def_hash_version = EXT2_HASH_HALF_MD4;
+ if (uuid_is_null((unsigned char *) sb->s_hash_seed))
+ uuid_generate((unsigned char *) sb->s_hash_seed);
+ }
+
+ if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+ if (ext2fs_check_desc(fs)) {
+ fputs(_("Clearing the flex_bg flag would "
+ "cause the the filesystem to be\n"
+ "inconsistent.\n"), stderr);
+ return 1;
+ }
+ }
+
+ if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
+ if ((mount_flags & EXT2_MF_MOUNTED) &&
+ !(mount_flags & EXT2_MF_READONLY)) {
+ fputs(_("The huge_file feature may only be "
+ "cleared when the filesystem is\n"
+ "unmounted or mounted "
+ "read-only.\n"), stderr);
+ return 1;
+ }
+ }
+
+ if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+ for (i = 0; i < fs->group_desc_count; i++) {
+ gd = ext2fs_group_desc(fs, fs->group_desc, i);
+ gd->bg_itable_unused = 0;
+ gd->bg_flags = EXT2_BG_INODE_ZEROED;
+ ext2fs_group_desc_csum_set(fs, i);
+ }
+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+ }
+
+ if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+ for (i = 0; i < fs->group_desc_count; i++) {
+ gd = ext2fs_group_desc(fs, fs->group_desc, i);
+ if ((gd->bg_flags & EXT2_BG_INODE_ZEROED) == 0) {
+ /*
+ * XXX what we really should do is zap
+ * uninitialized inode tables instead.
+ */
+ request_fsck_afterwards(fs);
+ break;
+ }
+ gd->bg_itable_unused = 0;
+ gd->bg_flags = 0;
+ gd->bg_checksum = 0;
+ }
+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+ }
+
+ if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
+ EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+ /*
+ * Set the Q_flag here and handle the quota options in the code
+ * below.
+ */
+ if (!Q_flag) {
+ Q_flag = 1;
+ /* Enable both user quota and group quota by default */
+ usrquota = QOPT_ENABLE;
+ grpquota = QOPT_ENABLE;
+ }
+ sb->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_QUOTA;
+ }
+
+ if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+ EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+ /*
+ * Set the Q_flag here and handle the quota options in the code
+ * below.
+ */
+ if (Q_flag)
+ fputs(_("\nWarning: '^quota' option overrides '-Q'"
+ "arguments.\n"), stderr);
+ Q_flag = 1;
+ /* Disable both user quota and group quota by default */
+ usrquota = QOPT_DISABLE;
+ grpquota = QOPT_DISABLE;
+ }
+
+ if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
+ (sb->s_feature_compat || sb->s_feature_ro_compat ||
+ sb->s_feature_incompat))
+ ext2fs_update_dynamic_rev(fs);
+
+ if (FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT,
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
+ FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
+ FEATURE_CHANGED(E2P_FEATURE_INCOMPAT,
+ EXT2_FEATURE_INCOMPAT_FILETYPE) ||
+ FEATURE_CHANGED(E2P_FEATURE_COMPAT,
+ EXT2_FEATURE_COMPAT_RESIZE_INODE) ||
+ FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE))
+ request_fsck_afterwards(fs);
+
+ if ((old_features[E2P_FEATURE_COMPAT] != sb->s_feature_compat) ||
+ (old_features[E2P_FEATURE_INCOMPAT] != sb->s_feature_incompat) ||
+ (old_features[E2P_FEATURE_RO_INCOMPAT] != sb->s_feature_ro_compat))
+ ext2fs_mark_super_dirty(fs);
+
+ return 0;
+}
+
+/*
+ * Add a journal to the filesystem.
+ */
+static int add_journal(ext2_filsys fs)
+{
+ unsigned long journal_blocks;
+ errcode_t retval;
+ ext2_filsys jfs;
+ io_manager io_ptr;
+
+ if (fs->super->s_feature_compat &
+ EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
+ fputs(_("The filesystem already has a journal.\n"), stderr);
+ goto err;
+ }
+ if (journal_device) {
+ check_plausibility(journal_device);
+ check_mount(journal_device, 0, _("journal"));
+#ifdef CONFIG_TESTIO_DEBUG
+ if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
+ io_ptr = test_io_manager;
+ test_io_backing_manager = unix_io_manager;
+ } else
+#endif
+ io_ptr = unix_io_manager;
+ retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
+ EXT2_FLAG_JOURNAL_DEV_OK, 0,
+ fs->blocksize, io_ptr, &jfs);
+ if (retval) {
+ com_err(program_name, retval,
+ _("\n\twhile trying to open journal on %s\n"),
+ journal_device);
+ goto err;
+ }
+ printf(_("Creating journal on device %s: "),
+ journal_device);
+ fflush(stdout);
+
+ retval = ext2fs_add_journal_device(fs, jfs);
+ ext2fs_close(jfs);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while adding filesystem to journal on %s"),
+ journal_device);
+ goto err;
+ }
+ fputs(_("done\n"), stdout);
+ } else if (journal_size) {
+ fputs(_("Creating journal inode: "), stdout);
+ fflush(stdout);
+ journal_blocks = figure_journal_size(journal_size, fs);
+
+ retval = ext2fs_add_journal_inode(fs, journal_blocks,
+ journal_flags);
+ if (retval) {
+ fprintf(stderr, "\n");
+ com_err(program_name, retval, "%s",
+ _("\n\twhile trying to create journal file"));
+ return retval;
+ } else
+ fputs(_("done\n"), stdout);
+ /*
+ * If the filesystem wasn't mounted, we need to force
+ * the block group descriptors out.
+ */
+ if ((mount_flags & EXT2_MF_MOUNTED) == 0)
+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+ }
+ print_check_message(fs->super->s_max_mnt_count,
+ fs->super->s_checkinterval);
+ return 0;
+
+err:
+ free(journal_device);
+ return 1;
+}
+
+static void handle_quota_options(ext2_filsys fs)
+{
+ quota_ctx_t qctx;
+ ext2_ino_t qf_ino;
+
+ if (!usrquota && !grpquota)
+ /* Nothing to do. */
+ return;
+
+ quota_init_context(&qctx, fs, -1);
+
+ if (usrquota == QOPT_ENABLE || grpquota == QOPT_ENABLE)
+ quota_compute_usage(qctx);
+
+ if (usrquota == QOPT_ENABLE && !fs->super->s_usr_quota_inum) {
+ if ((qf_ino = quota_file_exists(fs, USRQUOTA,
+ QFMT_VFS_V1)) > 0)
+ quota_update_limits(qctx, qf_ino, USRQUOTA);
+ quota_write_inode(qctx, USRQUOTA);
+ } else if (usrquota == QOPT_DISABLE) {
+ quota_remove_inode(fs, USRQUOTA);
+ }
+
+ if (grpquota == QOPT_ENABLE && !fs->super->s_grp_quota_inum) {
+ if ((qf_ino = quota_file_exists(fs, GRPQUOTA,
+ QFMT_VFS_V1)) > 0)
+ quota_update_limits(qctx, qf_ino, GRPQUOTA);
+ quota_write_inode(qctx, GRPQUOTA);
+ } else if (grpquota == QOPT_DISABLE) {
+ quota_remove_inode(fs, GRPQUOTA);
+ }
+
+ quota_release_context(&qctx);
+
+ if ((usrquota == QOPT_ENABLE) || (grpquota == QOPT_ENABLE)) {
+ fprintf(stderr, "%s", _("\nWarning: the quota feature is still "
+ "under development\n"
+ "See https://ext4.wiki.kernel.org/"
+ "index.php/Quota for more information\n\n"));
+ fs->super->s_feature_ro_compat |= EXT4_FEATURE_RO_COMPAT_QUOTA;
+ ext2fs_mark_super_dirty(fs);
+ } else if (!fs->super->s_usr_quota_inum &&
+ !fs->super->s_grp_quota_inum) {
+ fs->super->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_QUOTA;
+ ext2fs_mark_super_dirty(fs);
+ }
+
+ return;
+}
+
+#ifdef CONFIG_QUOTA
+static void parse_quota_opts(const char *opts)
+{
+ char *buf, *token, *next, *p;
+ int len;
+
+ len = strlen(opts);
+ buf = malloc(len+1);
+ if (!buf) {
+ fputs(_("Couldn't allocate memory to parse quota "
+ "options!\n"), stderr);
+ exit(1);
+ }
+ strcpy(buf, opts);
+ for (token = buf; token && *token; token = next) {
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+
+ if (strcmp(token, "usrquota") == 0) {
+ usrquota = QOPT_ENABLE;
+ } else if (strcmp(token, "^usrquota") == 0) {
+ usrquota = QOPT_DISABLE;
+ } else if (strcmp(token, "grpquota") == 0) {
+ grpquota = QOPT_ENABLE;
+ } else if (strcmp(token, "^grpquota") == 0) {
+ grpquota = QOPT_DISABLE;
+ } else {
+ fputs(_("\nBad quota options specified.\n\n"
+ "Following valid quota options are available "
+ "(pass by separating with comma):\n"
+ "\t[^]usrquota\n"
+ "\t[^]grpquota\n"
+ "\n\n"), stderr);
+ free(buf);
+ exit(1);
+ }
+ }
+ free(buf);
+}
+#endif
+
+static void parse_e2label_options(int argc, char ** argv)
+{
+ if ((argc < 2) || (argc > 3)) {
+ fputs(_("Usage: e2label device [newlabel]\n"), stderr);
+ exit(1);
+ }
+ io_options = strchr(argv[1], '?');
+ if (io_options)
+ *io_options++ = 0;
+ device_name = blkid_get_devname(NULL, argv[1], NULL);
+ if (!device_name) {
+ com_err("e2label", 0, _("Unable to resolve '%s'"),
+ argv[1]);
+ exit(1);
+ }
+ open_flag = EXT2_FLAG_JOURNAL_DEV_OK;
+ if (argc == 3) {
+ open_flag |= EXT2_FLAG_RW;
+ L_flag = 1;
+ new_label = argv[2];
+ } else
+ print_label++;
+}
+
+static time_t parse_time(char *str)
+{
+ struct tm ts;
+
+ if (strcmp(str, "now") == 0) {
+ return (time(0));
+ }
+ memset(&ts, 0, sizeof(ts));
+#ifdef HAVE_STRPTIME
+ strptime(str, "%Y%m%d%H%M%S", &ts);
+#else
+ sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
+ &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
+ ts.tm_year -= 1900;
+ ts.tm_mon -= 1;
+ if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 ||
+ ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 ||
+ ts.tm_min > 59 || ts.tm_sec > 61)
+ ts.tm_mday = 0;
+#endif
+ if (ts.tm_mday == 0) {
+ com_err(program_name, 0,
+ _("Couldn't parse date/time specifier: %s"),
+ str);
+ usage();
+ }
+ ts.tm_isdst = -1;
+ return (mktime(&ts));
+}
+
+static void parse_tune2fs_options(int argc, char **argv)
+{
+ int c;
+ char *tmp;
+ struct group *gr;
+ struct passwd *pw;
+ char optstring[100] = "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:";
+
+#ifdef CONFIG_QUOTA
+ strcat(optstring, "Q:");
+#endif
+ open_flag = 0;
+
+ printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
+ while ((c = getopt(argc, argv, optstring)) != EOF)
+ switch (c) {
+ case 'c':
+ max_mount_count = strtol(optarg, &tmp, 0);
+ if (*tmp || max_mount_count > 16000) {
+ com_err(program_name, 0,
+ _("bad mounts count - %s"),
+ optarg);
+ usage();
+ }
+ if (max_mount_count == 0)
+ max_mount_count = -1;
+ c_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'C':
+ mount_count = strtoul(optarg, &tmp, 0);
+ if (*tmp || mount_count > 16000) {
+ com_err(program_name, 0,
+ _("bad mounts count - %s"),
+ optarg);
+ usage();
+ }
+ C_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'e':
+ if (strcmp(optarg, "continue") == 0)
+ errors = EXT2_ERRORS_CONTINUE;
+ else if (strcmp(optarg, "remount-ro") == 0)
+ errors = EXT2_ERRORS_RO;
+ else if (strcmp(optarg, "panic") == 0)
+ errors = EXT2_ERRORS_PANIC;
+ else {
+ com_err(program_name, 0,
+ _("bad error behavior - %s"),
+ optarg);
+ usage();
+ }
+ e_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'E':
+ extended_cmd = optarg;
+ open_flag |= EXT2_FLAG_RW;
+ break;
+ case 'f': /* Force */
+ f_flag = 1;
+ break;
+ case 'g':
+ resgid = strtoul(optarg, &tmp, 0);
+ if (*tmp) {
+ gr = getgrnam(optarg);
+ if (gr == NULL)
+ tmp = optarg;
+ else {
+ resgid = gr->gr_gid;
+ *tmp = 0;
+ }
+ }
+ if (*tmp) {
+ com_err(program_name, 0,
+ _("bad gid/group name - %s"),
+ optarg);
+ usage();
+ }
+ g_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'i':
+ interval = strtoul(optarg, &tmp, 0);
+ switch (*tmp) {
+ case 's':
+ tmp++;
+ break;
+ case '\0':
+ case 'd':
+ case 'D': /* days */
+ interval *= 86400;
+ if (*tmp != '\0')
+ tmp++;
+ break;
+ case 'm':
+ case 'M': /* months! */
+ interval *= 86400 * 30;
+ tmp++;
+ break;
+ case 'w':
+ case 'W': /* weeks */
+ interval *= 86400 * 7;
+ tmp++;
+ break;
+ }
+ if (*tmp) {
+ com_err(program_name, 0,
+ _("bad interval - %s"), optarg);
+ usage();
+ }
+ i_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'j':
+ if (!journal_size)
+ journal_size = -1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'J':
+ parse_journal_opts(optarg);
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'l':
+ l_flag = 1;
+ break;
+ case 'L':
+ new_label = optarg;
+ L_flag = 1;
+ open_flag |= EXT2_FLAG_RW |
+ EXT2_FLAG_JOURNAL_DEV_OK;
+ break;
+ case 'm':
+ reserved_ratio = strtod(optarg, &tmp);
+ if (*tmp || reserved_ratio > 50 ||
+ reserved_ratio < 0) {
+ com_err(program_name, 0,
+ _("bad reserved block ratio - %s"),
+ optarg);
+ usage();
+ }
+ m_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'M':
+ new_last_mounted = optarg;
+ M_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'o':
+ if (mntopts_cmd) {
+ com_err(program_name, 0, "%s",
+ _("-o may only be specified once"));
+ usage();
+ }
+ mntopts_cmd = optarg;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'O':
+ if (features_cmd) {
+ com_err(program_name, 0, "%s",
+ _("-O may only be specified once"));
+ usage();
+ }
+ features_cmd = optarg;
+ open_flag = EXT2_FLAG_RW;
+ break;
+#ifdef CONFIG_QUOTA
+ case 'Q':
+ Q_flag = 1;
+ parse_quota_opts(optarg);
+ open_flag = EXT2_FLAG_RW;
+ break;
+#endif
+ case 'r':
+ reserved_blocks = strtoul(optarg, &tmp, 0);
+ if (*tmp) {
+ com_err(program_name, 0,
+ _("bad reserved blocks count - %s"),
+ optarg);
+ usage();
+ }
+ r_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 's': /* Deprecated */
+ s_flag = atoi(optarg);
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'T':
+ T_flag = 1;
+ last_check_time = parse_time(optarg);
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'u':
+ resuid = strtoul(optarg, &tmp, 0);
+ if (*tmp) {
+ pw = getpwnam(optarg);
+ if (pw == NULL)
+ tmp = optarg;
+ else {
+ resuid = pw->pw_uid;
+ *tmp = 0;
+ }
+ }
+ if (*tmp) {
+ com_err(program_name, 0,
+ _("bad uid/user name - %s"),
+ optarg);
+ usage();
+ }
+ u_flag = 1;
+ open_flag = EXT2_FLAG_RW;
+ break;
+ case 'U':
+ new_UUID = optarg;
+ U_flag = 1;
+ open_flag = EXT2_FLAG_RW |
+ EXT2_FLAG_JOURNAL_DEV_OK;
+ break;
+ case 'I':
+ new_inode_size = strtoul(optarg, &tmp, 0);
+ if (*tmp) {
+ com_err(program_name, 0,
+ _("bad inode size - %s"),
+ optarg);
+ usage();
+ }
+ if (!((new_inode_size &
+ (new_inode_size - 1)) == 0)) {
+ com_err(program_name, 0,
+ _("Inode size must be a "
+ "power of two- %s"),
+ optarg);
+ usage();
+ }
+ open_flag = EXT2_FLAG_RW;
+ I_flag = 1;
+ break;
+ default:
+ usage();
+ }
+ if (optind < argc - 1 || optind == argc)
+ usage();
+ if (!open_flag && !l_flag)
+ usage();
+ io_options = strchr(argv[optind], '?');
+ if (io_options)
+ *io_options++ = 0;
+ device_name = blkid_get_devname(NULL, argv[optind], NULL);
+ if (!device_name) {
+ com_err(program_name, 0, _("Unable to resolve '%s'"),
+ argv[optind]);
+ exit(1);
+ }
+}
+
+#ifdef CONFIG_BUILD_FINDFS
+void do_findfs(int argc, char **argv)
+{
+ char *dev;
+
+ if ((argc != 2) ||
+ (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) {
+ fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n");
+ exit(2);
+ }
+ dev = blkid_get_devname(NULL, argv[1], NULL);
+ if (!dev) {
+ com_err("findfs", 0, _("Unable to resolve '%s'"),
+ argv[1]);
+ exit(1);
+ }
+ puts(dev);
+ exit(0);
+}
+#endif
+
+static int parse_extended_opts(ext2_filsys fs, const char *opts)
+{
+ char *buf, *token, *next, *p, *arg;
+ int len, hash_alg;
+ int r_usage = 0;
+
+ len = strlen(opts);
+ buf = malloc(len+1);
+ if (!buf) {
+ fprintf(stderr, "%s",
+ _("Couldn't allocate memory to parse options!\n"));
+ return 1;
+ }
+ strcpy(buf, opts);
+ for (token = buf; token && *token; token = next) {
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+ arg = strchr(token, '=');
+ if (arg) {
+ *arg = 0;
+ arg++;
+ }
+ if (strcmp(token, "clear-mmp") == 0 ||
+ strcmp(token, "clear_mmp") == 0) {
+ clear_mmp = 1;
+ } else if (strcmp(token, "mmp_update_interval") == 0) {
+ unsigned long intv;
+ if (!arg) {
+ r_usage++;
+ continue;
+ }
+ intv = strtoul(arg, &p, 0);
+ if (*p) {
+ fprintf(stderr,
+ _("Invalid mmp_update_interval: %s\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ if (intv == 0) {
+ intv = EXT4_MMP_UPDATE_INTERVAL;
+ } else if (intv > EXT4_MMP_MAX_UPDATE_INTERVAL) {
+ fprintf(stderr,
+ _("mmp_update_interval too big: %lu\n"),
+ intv);
+ r_usage++;
+ continue;
+ }
+ printf(P_("Setting multiple mount protection update "
+ "interval to %lu second\n",
+ "Setting multiple mount protection update "
+ "interval to %lu seconds\n", intv),
+ intv);
+ fs->super->s_mmp_update_interval = intv;
+ ext2fs_mark_super_dirty(fs);
+ } else if (!strcmp(token, "test_fs")) {
+ fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS;
+ printf("Setting test filesystem flag\n");
+ ext2fs_mark_super_dirty(fs);
+ } else if (!strcmp(token, "^test_fs")) {
+ fs->super->s_flags &= ~EXT2_FLAGS_TEST_FILESYS;
+ printf("Clearing test filesystem flag\n");
+ ext2fs_mark_super_dirty(fs);
+ } else if (strcmp(token, "stride") == 0) {
+ if (!arg) {
+ r_usage++;
+ continue;
+ }
+ stride = strtoul(arg, &p, 0);
+ if (*p) {
+ fprintf(stderr,
+ _("Invalid RAID stride: %s\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ stride_set = 1;
+ } else if (strcmp(token, "stripe-width") == 0 ||
+ strcmp(token, "stripe_width") == 0) {
+ if (!arg) {
+ r_usage++;
+ continue;
+ }
+ stripe_width = strtoul(arg, &p, 0);
+ if (*p) {
+ fprintf(stderr,
+ _("Invalid RAID stripe-width: %s\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ stripe_width_set = 1;
+ } else if (strcmp(token, "hash_alg") == 0 ||
+ strcmp(token, "hash-alg") == 0) {
+ if (!arg) {
+ r_usage++;
+ continue;
+ }
+ hash_alg = e2p_string2hash(arg);
+ if (hash_alg < 0) {
+ fprintf(stderr,
+ _("Invalid hash algorithm: %s\n"),
+ arg);
+ r_usage++;
+ continue;
+ }
+ fs->super->s_def_hash_version = hash_alg;
+ printf(_("Setting default hash algorithm "
+ "to %s (%d)\n"),
+ arg, hash_alg);
+ ext2fs_mark_super_dirty(fs);
+ } else if (!strcmp(token, "mount_opts")) {
+ if (!arg) {
+ r_usage++;
+ continue;
+ }
+ if (strlen(arg) >= sizeof(fs->super->s_mount_opts)) {
+ fprintf(stderr,
+ "Extended mount options too long\n");
+ continue;
+ }
+ ext_mount_opts = strdup(arg);
+ } else
+ r_usage++;
+ }
+ if (r_usage) {
+ fprintf(stderr, "%s", _("\nBad options specified.\n\n"
+ "Extended options are separated by commas, "
+ "and may take an argument which\n"
+ "\tis set off by an equals ('=') sign.\n\n"
+ "Valid extended options are:\n"
+ "\tclear_mmp\n"
+ "\thash_alg=<hash algorithm>\n"
+ "\tmount_opts=<extended default mount options>\n"
+ "\tstride=<RAID per-disk chunk size in blocks>\n"
+ "\tstripe_width=<RAID stride*data disks in blocks>\n"
+ "\ttest_fs\n"
+ "\t^test_fs\n"));
+ free(buf);
+ return 1;
+ }
+ free(buf);
+
+ return 0;
+}
+
+/*
+ * Fill in the block bitmap bmap with the information regarding the
+ * blocks to be moved
+ */
+static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp,
+ ext2fs_block_bitmap bmap)
+{
+ dgrp_t i;
+ int retval;
+ ext2_badblocks_list bb_list = 0;
+ blk64_t j, needed_blocks = 0;
+ blk64_t start_blk, end_blk;
+
+ retval = ext2fs_read_bb_inode(fs, &bb_list);
+ if (retval)
+ return retval;
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ start_blk = ext2fs_inode_table_loc(fs, i) +
+ fs->inode_blocks_per_group;
+
+ end_blk = ext2fs_inode_table_loc(fs, i) +
+ new_ino_blks_per_grp;
+
+ for (j = start_blk; j < end_blk; j++) {
+ if (ext2fs_test_block_bitmap2(fs->block_map, j)) {
+ /*
+ * IF the block is a bad block we fail
+ */
+ if (ext2fs_badblocks_list_test(bb_list, j)) {
+ ext2fs_badblocks_list_free(bb_list);
+ return ENOSPC;
+ }
+
+ ext2fs_mark_block_bitmap2(bmap, j);
+ } else {
+ /*
+ * We are going to use this block for
+ * inode table. So mark them used.
+ */
+ ext2fs_mark_block_bitmap2(fs->block_map, j);
+ }
+ }
+ needed_blocks += end_blk - start_blk;
+ }
+
+ ext2fs_badblocks_list_free(bb_list);
+ if (needed_blocks > ext2fs_free_blocks_count(fs->super))
+ return ENOSPC;
+
+ return 0;
+}
+
+static int ext2fs_is_meta_block(ext2_filsys fs, blk64_t blk)
+{
+ dgrp_t group;
+ group = ext2fs_group_of_blk2(fs, blk);
+ if (ext2fs_block_bitmap_loc(fs, group) == blk)
+ return 1;
+ if (ext2fs_inode_bitmap_loc(fs, group) == blk)
+ return 1;
+ return 0;
+}
+
+static int ext2fs_is_block_in_group(ext2_filsys fs, dgrp_t group, blk64_t blk)
+{
+ blk64_t start_blk, end_blk;
+ start_blk = fs->super->s_first_data_block +
+ EXT2_BLOCKS_PER_GROUP(fs->super) * group;
+ /*
+ * We cannot get new block beyond end_blk for for the last block group
+ * so we can check with EXT2_BLOCKS_PER_GROUP even for last block group
+ */
+ end_blk = start_blk + EXT2_BLOCKS_PER_GROUP(fs->super);
+ if (blk >= start_blk && blk <= end_blk)
+ return 1;
+ return 0;
+}
+
+static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
+{
+
+ char *buf;
+ dgrp_t group = 0;
+ errcode_t retval;
+ int meta_data = 0;
+ blk64_t blk, new_blk, goal;
+ struct blk_move *bmv;
+
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return retval;
+
+ for (new_blk = blk = fs->super->s_first_data_block;
+ blk < ext2fs_blocks_count(fs->super); blk++) {
+ if (!ext2fs_test_block_bitmap2(bmap, blk))
+ continue;
+
+ if (ext2fs_is_meta_block(fs, blk)) {
+ /*
+ * If the block is mapping a fs meta data block
+ * like group desc/block bitmap/inode bitmap. We
+ * should find a block in the same group and fix
+ * the respective fs metadata pointers. Otherwise
+ * fail
+ */
+ group = ext2fs_group_of_blk2(fs, blk);
+ goal = ext2fs_group_first_block2(fs, group);
+ meta_data = 1;
+
+ } else {
+ goal = new_blk;
+ }
+ retval = ext2fs_new_block2(fs, goal, NULL, &new_blk);
+ if (retval)
+ goto err_out;
+
+ /* new fs meta data block should be in the same group */
+ if (meta_data && !ext2fs_is_block_in_group(fs, group, new_blk)) {
+ retval = ENOSPC;
+ goto err_out;
+ }
+
+ /* Mark this block as allocated */
+ ext2fs_mark_block_bitmap2(fs->block_map, new_blk);
+
+ /* Add it to block move list */
+ retval = ext2fs_get_mem(sizeof(struct blk_move), &bmv);
+ if (retval)
+ goto err_out;
+
+ bmv->old_loc = blk;
+ bmv->new_loc = new_blk;
+
+ list_add(&(bmv->list), &blk_move_list);
+
+ retval = io_channel_read_blk64(fs->io, blk, 1, buf);
+ if (retval)
+ goto err_out;
+
+ retval = io_channel_write_blk64(fs->io, new_blk, 1, buf);
+ if (retval)
+ goto err_out;
+ }
+
+err_out:
+ ext2fs_free_mem(&buf);
+ return retval;
+}
+
+static blk64_t translate_block(blk64_t blk)
+{
+ struct list_head *entry;
+ struct blk_move *bmv;
+
+ list_for_each(entry, &blk_move_list) {
+ bmv = list_entry(entry, struct blk_move, list);
+ if (bmv->old_loc == blk)
+ return bmv->new_loc;
+ }
+
+ return 0;
+}
+
+static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)),
+ blk64_t *block_nr,
+ e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
+ blk64_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *priv_data)
+{
+ int ret = 0;
+ blk64_t new_blk;
+ ext2fs_block_bitmap bmap = (ext2fs_block_bitmap) priv_data;
+
+ if (!ext2fs_test_block_bitmap2(bmap, *block_nr))
+ return 0;
+ new_blk = translate_block(*block_nr);
+ if (new_blk) {
+ *block_nr = new_blk;
+ /*
+ * This will force the ext2fs_write_inode in the iterator
+ */
+ ret |= BLOCK_CHANGED;
+ }
+
+ return ret;
+}
+
+static int inode_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
+{
+ errcode_t retval = 0;
+ ext2_ino_t ino;
+ blk64_t blk;
+ char *block_buf = 0;
+ struct ext2_inode inode;
+ ext2_inode_scan scan = NULL;
+
+ retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_open_inode_scan(fs, 0, &scan);
+ if (retval)
+ goto err_out;
+
+ while (1) {
+ retval = ext2fs_get_next_inode(scan, &ino, &inode);
+ if (retval)
+ goto err_out;
+
+ if (!ino)
+ break;
+
+ if (inode.i_links_count == 0)
+ continue; /* inode not in use */
+
+ /* FIXME!!
+ * If we end up modifying the journal inode
+ * the sb->s_jnl_blocks will differ. But a
+ * subsequent e2fsck fixes that.
+ * Do we need to fix this ??
+ */
+
+ if (ext2fs_file_acl_block(fs, &inode) &&
+ ext2fs_test_block_bitmap2(bmap,
+ ext2fs_file_acl_block(fs, &inode))) {
+ blk = translate_block(ext2fs_file_acl_block(fs,
+ &inode));
+ if (!blk)
+ continue;
+
+ ext2fs_file_acl_block_set(fs, &inode, blk);
+
+ /*
+ * Write the inode to disk so that inode table
+ * resizing can work
+ */
+ retval = ext2fs_write_inode(fs, ino, &inode);
+ if (retval)
+ goto err_out;
+ }
+
+ if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
+ continue;
+
+ retval = ext2fs_block_iterate3(fs, ino, 0, block_buf,
+ process_block, bmap);
+ if (retval)
+ goto err_out;
+
+ }
+
+err_out:
+ ext2fs_free_mem(&block_buf);
+
+ return retval;
+}
+
+/*
+ * We need to scan for inode and block bitmaps that may need to be
+ * moved. This can take place if the filesystem was formatted for
+ * RAID arrays using the mke2fs's extended option "stride".
+ */
+static int group_desc_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
+{
+ dgrp_t i;
+ blk64_t blk, new_blk;
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ blk = ext2fs_block_bitmap_loc(fs, i);
+ if (ext2fs_test_block_bitmap2(bmap, blk)) {
+ new_blk = translate_block(blk);
+ if (!new_blk)
+ continue;
+ ext2fs_block_bitmap_loc_set(fs, i, new_blk);
+ }
+
+ blk = ext2fs_inode_bitmap_loc(fs, i);
+ if (ext2fs_test_block_bitmap2(bmap, blk)) {
+ new_blk = translate_block(blk);
+ if (!new_blk)
+ continue;
+ ext2fs_inode_bitmap_loc_set(fs, i, new_blk);
+ }
+ }
+ return 0;
+}
+
+static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size)
+{
+ dgrp_t i;
+ blk64_t blk;
+ errcode_t retval;
+ int new_ino_blks_per_grp;
+ unsigned int j;
+ char *old_itable = NULL, *new_itable = NULL;
+ char *tmp_old_itable = NULL, *tmp_new_itable = NULL;
+ unsigned long old_ino_size;
+ int old_itable_size, new_itable_size;
+
+ old_itable_size = fs->inode_blocks_per_group * fs->blocksize;
+ old_ino_size = EXT2_INODE_SIZE(fs->super);
+
+ new_ino_blks_per_grp = ext2fs_div_ceil(
+ EXT2_INODES_PER_GROUP(fs->super) *
+ new_ino_size,
+ fs->blocksize);
+
+ new_itable_size = new_ino_blks_per_grp * fs->blocksize;
+
+ retval = ext2fs_get_mem(old_itable_size, &old_itable);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_get_mem(new_itable_size, &new_itable);
+ if (retval)
+ goto err_out;
+
+ tmp_old_itable = old_itable;
+ tmp_new_itable = new_itable;
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ blk = ext2fs_inode_table_loc(fs, i);
+ retval = io_channel_read_blk64(fs->io, blk,
+ fs->inode_blocks_per_group, old_itable);
+ if (retval)
+ goto err_out;
+
+ for (j = 0; j < EXT2_INODES_PER_GROUP(fs->super); j++) {
+ memcpy(new_itable, old_itable, old_ino_size);
+
+ memset(new_itable+old_ino_size, 0,
+ new_ino_size - old_ino_size);
+
+ new_itable += new_ino_size;
+ old_itable += old_ino_size;
+ }
+
+ /* reset the pointer */
+ old_itable = tmp_old_itable;
+ new_itable = tmp_new_itable;
+
+ retval = io_channel_write_blk64(fs->io, blk,
+ new_ino_blks_per_grp, new_itable);
+ if (retval)
+ goto err_out;
+ }
+
+ /* Update the meta data */
+ fs->inode_blocks_per_group = new_ino_blks_per_grp;
+ fs->super->s_inode_size = new_ino_size;
+
+err_out:
+ if (old_itable)
+ ext2fs_free_mem(&old_itable);
+
+ if (new_itable)
+ ext2fs_free_mem(&new_itable);
+
+ return retval;
+}
+
+static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
+{
+ blk64_t blk;
+ ext2_ino_t ino;
+ unsigned int group = 0;
+ unsigned int count = 0;
+ int total_free = 0;
+ int group_free = 0;
+
+ /*
+ * First calculate the block statistics
+ */
+ for (blk = fs->super->s_first_data_block;
+ blk < ext2fs_blocks_count(fs->super); blk++) {
+ if (!ext2fs_fast_test_block_bitmap2(fs->block_map, blk)) {
+ group_free++;
+ total_free++;
+ }
+ count++;
+ if ((count == fs->super->s_blocks_per_group) ||
+ (blk == ext2fs_blocks_count(fs->super)-1)) {
+ ext2fs_bg_free_blocks_count_set(fs, group++,
+ group_free);
+ count = 0;
+ group_free = 0;
+ }
+ }
+ total_free = EXT2FS_C2B(fs, total_free);
+ ext2fs_free_blocks_count_set(fs->super, total_free);
+
+ /*
+ * Next, calculate the inode statistics
+ */
+ group_free = 0;
+ total_free = 0;
+ count = 0;
+ group = 0;
+
+ /* Protect loop from wrap-around if s_inodes_count maxed */
+ for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
+ if (!ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
+ group_free++;
+ total_free++;
+ }
+ count++;
+ if ((count == fs->super->s_inodes_per_group) ||
+ (ino == fs->super->s_inodes_count)) {
+ ext2fs_bg_free_inodes_count_set(fs, group++,
+ group_free);
+ count = 0;
+ group_free = 0;
+ }
+ }
+ fs->super->s_free_inodes_count = total_free;
+ ext2fs_mark_super_dirty(fs);
+ return 0;
+}
+
+#define list_for_each_safe(pos, pnext, head) \
+ for (pos = (head)->next, pnext = pos->next; pos != (head); \
+ pos = pnext, pnext = pos->next)
+
+static void free_blk_move_list(void)
+{
+ struct list_head *entry, *tmp;
+ struct blk_move *bmv;
+
+ list_for_each_safe(entry, tmp, &blk_move_list) {
+ bmv = list_entry(entry, struct blk_move, list);
+ list_del(entry);
+ ext2fs_free_mem(&bmv);
+ }
+ return;
+}
+
+static int resize_inode(ext2_filsys fs, unsigned long new_size)
+{
+ errcode_t retval;
+ int new_ino_blks_per_grp;
+ ext2fs_block_bitmap bmap;
+
+ retval = ext2fs_read_inode_bitmap(fs);
+ if (retval) {
+ fputs(_("Failed to read inode bitmap\n"), stderr);
+ return retval;
+ }
+ retval = ext2fs_read_block_bitmap(fs);
+ if (retval) {
+ fputs(_("Failed to read block bitmap\n"), stderr);
+ return retval;
+ }
+ INIT_LIST_HEAD(&blk_move_list);
+
+
+ new_ino_blks_per_grp = ext2fs_div_ceil(
+ EXT2_INODES_PER_GROUP(fs->super)*
+ new_size,
+ fs->blocksize);
+
+ /* We may change the file system.
+ * Mark the file system as invalid so that
+ * the user is prompted to run fsck.
+ */
+ fs->super->s_state &= ~EXT2_VALID_FS;
+
+ retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
+ &bmap);
+ if (retval) {
+ fputs(_("Failed to allocate block bitmap when "
+ "increasing inode size\n"), stderr);
+ return retval;
+ }
+ retval = get_move_bitmaps(fs, new_ino_blks_per_grp, bmap);
+ if (retval) {
+ fputs(_("Not enough space to increase inode size \n"), stderr);
+ goto err_out;
+ }
+ retval = move_block(fs, bmap);
+ if (retval) {
+ fputs(_("Failed to relocate blocks during inode resize \n"),
+ stderr);
+ goto err_out;
+ }
+ retval = inode_scan_and_fix(fs, bmap);
+ if (retval)
+ goto err_out_undo;
+
+ retval = group_desc_scan_and_fix(fs, bmap);
+ if (retval)
+ goto err_out_undo;
+
+ retval = expand_inode_table(fs, new_size);
+ if (retval)
+ goto err_out_undo;
+
+ ext2fs_calculate_summary_stats(fs);
+
+ fs->super->s_state |= EXT2_VALID_FS;
+ /* mark super block and block bitmap as dirty */
+ ext2fs_mark_super_dirty(fs);
+ ext2fs_mark_bb_dirty(fs);
+
+err_out:
+ free_blk_move_list();
+ ext2fs_free_block_bitmap(bmap);
+
+ return retval;
+
+err_out_undo:
+ free_blk_move_list();
+ ext2fs_free_block_bitmap(bmap);
+ fputs(_("Error in resizing the inode size.\n"
+ "Run e2undo to undo the "
+ "file system changes. \n"), stderr);
+
+ return retval;
+}
+
+static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
+{
+ errcode_t retval = 0;
+ const char *tdb_dir;
+ char *tdb_file;
+ char *dev_name, *tmp_name;
+
+#if 0 /* FIXME!! */
+ /*
+ * Configuration via a conf file would be
+ * nice
+ */
+ profile_get_string(profile, "scratch_files",
+ "directory", 0, 0,
+ &tdb_dir);
+#endif
+ tmp_name = strdup(name);
+ if (!tmp_name) {
+ alloc_fn_fail:
+ com_err(program_name, ENOMEM, "%s",
+ _("Couldn't allocate memory for tdb filename\n"));
+ return ENOMEM;
+ }
+ dev_name = basename(tmp_name);
+
+ tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
+ if (!tdb_dir)
+ tdb_dir = "/var/lib/e2fsprogs";
+
+ if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
+ access(tdb_dir, W_OK))
+ return 0;
+
+ tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1);
+ if (!tdb_file)
+ goto alloc_fn_fail;
+ sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name);
+
+ if (!access(tdb_file, F_OK)) {
+ if (unlink(tdb_file) < 0) {
+ retval = errno;
+ com_err(program_name, retval,
+ _("while trying to delete %s"),
+ tdb_file);
+ free(tdb_file);
+ return retval;
+ }
+ }
+
+ set_undo_io_backing_manager(*io_ptr);
+ *io_ptr = undo_io_manager;
+ set_undo_io_backup_file(tdb_file);
+ printf(_("To undo the tune2fs operation please run "
+ "the command\n e2undo %s %s\n\n"),
+ tdb_file, name);
+ free(tdb_file);
+ free(tmp_name);
+ return retval;
+}
+
+int main(int argc, char **argv)
+{
+ errcode_t retval;
+ ext2_filsys fs;
+ struct ext2_super_block *sb;
+ io_manager io_ptr, io_ptr_orig = NULL;
+ int rc = 0;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+ set_com_err_gettext(gettext);
+#endif
+ if (argc && *argv)
+ program_name = *argv;
+ add_error_table(&et_ext2_error_table);
+
+#ifdef CONFIG_BUILD_FINDFS
+ if (strcmp(get_progname(argv[0]), "findfs") == 0)
+ do_findfs(argc, argv);
+#endif
+ if (strcmp(get_progname(argv[0]), "e2label") == 0)
+ parse_e2label_options(argc, argv);
+ else
+ parse_tune2fs_options(argc, argv);
+
+#ifdef CONFIG_TESTIO_DEBUG
+ if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_DEBUG")) {
+ io_ptr = test_io_manager;
+ test_io_backing_manager = unix_io_manager;
+ } else
+#endif
+ io_ptr = unix_io_manager;
+
+retry_open:
+ if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag)
+ open_flag |= EXT2_FLAG_SKIP_MMP;
+
+ open_flag |= EXT2_FLAG_64BITS;
+
+ /* keep the filesystem struct around to dump MMP data */
+ open_flag |= EXT2_FLAG_NOFREE_ON_ERROR;
+
+ retval = ext2fs_open2(device_name, io_options, open_flag,
+ 0, 0, io_ptr, &fs);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while trying to open %s"),
+ device_name);
+ if (retval == EXT2_ET_MMP_FSCK_ON ||
+ retval == EXT2_ET_MMP_UNKNOWN_SEQ)
+ dump_mmp_msg(fs->mmp_buf,
+ _("If you are sure the filesystem "
+ "is not in use on any node, run:\n"
+ "'tune2fs -f -E clear_mmp {device}'\n"));
+ else if (retval == EXT2_ET_MMP_FAILED)
+ dump_mmp_msg(fs->mmp_buf, NULL);
+ else if (retval == EXT2_ET_MMP_MAGIC_INVALID)
+ fprintf(stderr,
+ _("MMP block magic is bad. Try to fix it by "
+ "running:\n'e2fsck -f %s'\n"), device_name);
+ else if (retval != EXT2_ET_MMP_FAILED)
+ fprintf(stderr, "%s",
+ _("Couldn't find valid filesystem superblock.\n"));
+
+ ext2fs_free(fs);
+ exit(1);
+ }
+ fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
+
+ if (I_flag && !io_ptr_orig) {
+ /*
+ * Check the inode size is right so we can issue an
+ * error message and bail before setting up the tdb
+ * file.
+ */
+ if (new_inode_size == EXT2_INODE_SIZE(fs->super)) {
+ fprintf(stderr, _("The inode size is already %lu\n"),
+ new_inode_size);
+ rc = 1;
+ goto closefs;
+ }
+ if (new_inode_size < EXT2_INODE_SIZE(fs->super)) {
+ fprintf(stderr, "%s",
+ _("Shrinking inode size is not supported\n"));
+ rc = 1;
+ goto closefs;
+ }
+ if (new_inode_size > fs->blocksize) {
+ fprintf(stderr, _("Invalid inode size %lu (max %d)\n"),
+ new_inode_size, fs->blocksize);
+ rc = 1;
+ goto closefs;
+ }
+
+ /*
+ * If inode resize is requested use the
+ * Undo I/O manager
+ */
+ io_ptr_orig = io_ptr;
+ retval = tune2fs_setup_tdb(device_name, &io_ptr);
+ if (retval) {
+ rc = 1;
+ goto closefs;
+ }
+ if (io_ptr != io_ptr_orig) {
+ ext2fs_close(fs);
+ goto retry_open;
+ }
+ }
+
+ sb = fs->super;
+ fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
+
+ if (print_label) {
+ /* For e2label emulation */
+ printf("%.*s\n", (int) sizeof(sb->s_volume_name),
+ sb->s_volume_name);
+ remove_error_table(&et_ext2_error_table);
+ goto closefs;
+ }
+
+ retval = ext2fs_check_if_mounted(device_name, &mount_flags);
+ if (retval) {
+ com_err("ext2fs_check_if_mount", retval,
+ _("while determining whether %s is mounted."),
+ device_name);
+ rc = 1;
+ goto closefs;
+ }
+ /* Normally we only need to write out the superblock */
+ fs->flags |= EXT2_FLAG_SUPER_ONLY;
+
+ if (c_flag) {
+ sb->s_max_mnt_count = max_mount_count;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting maximal mount count to %d\n"),
+ max_mount_count);
+ }
+ if (C_flag) {
+ sb->s_mnt_count = mount_count;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting current mount count to %d\n"), mount_count);
+ }
+ if (e_flag) {
+ sb->s_errors = errors;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting error behavior to %d\n"), errors);
+ }
+ if (g_flag) {
+ sb->s_def_resgid = resgid;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting reserved blocks gid to %lu\n"), resgid);
+ }
+ if (i_flag) {
+ if (interval >= (1ULL << 32)) {
+ com_err(program_name, 0,
+ _("interval between checks is too big (%lu)"),
+ interval);
+ rc = 1;
+ goto closefs;
+ }
+ sb->s_checkinterval = interval;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting interval between checks to %lu seconds\n"),
+ interval);
+ }
+ if (m_flag) {
+ ext2fs_r_blocks_count_set(sb, reserved_ratio *
+ ext2fs_blocks_count(sb) / 100.0);
+ ext2fs_mark_super_dirty(fs);
+ printf (_("Setting reserved blocks percentage to %g%% (%llu blocks)\n"),
+ reserved_ratio, ext2fs_r_blocks_count(sb));
+ }
+ if (r_flag) {
+ if (reserved_blocks > ext2fs_blocks_count(sb)/2) {
+ com_err(program_name, 0,
+ _("reserved blocks count is too big (%llu)"),
+ reserved_blocks);
+ rc = 1;
+ goto closefs;
+ }
+ ext2fs_r_blocks_count_set(sb, reserved_blocks);
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting reserved blocks count to %llu\n"),
+ reserved_blocks);
+ }
+ if (s_flag == 1) {
+ if (sb->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
+ fputs(_("\nThe filesystem already has sparse "
+ "superblocks.\n"), stderr);
+ else {
+ sb->s_feature_ro_compat |=
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
+ sb->s_state &= ~EXT2_VALID_FS;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("\nSparse superblock flag set. %s"),
+ _(please_fsck));
+ }
+ }
+ if (s_flag == 0) {
+ fputs(_("\nClearing the sparse superflag not supported.\n"),
+ stderr);
+ rc = 1;
+ goto closefs;
+ }
+ if (T_flag) {
+ sb->s_lastcheck = last_check_time;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting time filesystem last checked to %s\n"),
+ ctime(&last_check_time));
+ }
+ if (u_flag) {
+ sb->s_def_resuid = resuid;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting reserved blocks uid to %lu\n"), resuid);
+ }
+ if (L_flag) {
+ if (strlen(new_label) > sizeof(sb->s_volume_name))
+ fputs(_("Warning: label too long, truncating.\n"),
+ stderr);
+ memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
+ strncpy(sb->s_volume_name, new_label,
+ sizeof(sb->s_volume_name));
+ ext2fs_mark_super_dirty(fs);
+ }
+ if (M_flag) {
+ memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
+ strncpy(sb->s_last_mounted, new_last_mounted,
+ sizeof(sb->s_last_mounted));
+ ext2fs_mark_super_dirty(fs);
+ }
+ if (mntopts_cmd) {
+ rc = update_mntopts(fs, mntopts_cmd);
+ if (rc)
+ goto closefs;
+ }
+ if (features_cmd) {
+ rc = update_feature_set(fs, features_cmd);
+ if (rc)
+ goto closefs;
+ }
+ if (extended_cmd) {
+ rc = parse_extended_opts(fs, extended_cmd);
+ if (rc)
+ goto closefs;
+ if (clear_mmp && !f_flag) {
+ fputs(_("Error in using clear_mmp. "
+ "It must be used with -f\n"),
+ stderr);
+ goto closefs;
+ }
+ }
+ if (clear_mmp) {
+ rc = ext2fs_mmp_clear(fs);
+ goto closefs;
+ }
+ if (journal_size || journal_device) {
+ rc = add_journal(fs);
+ if (rc)
+ goto closefs;
+ }
+
+ if (Q_flag) {
+ if (mount_flags & EXT2_MF_MOUNTED) {
+ fputs(_("The quota feature may only be changed when "
+ "the filesystem is unmounted.\n"), stderr);
+ rc = 1;
+ goto closefs;
+ }
+ handle_quota_options(fs);
+ }
+
+ if (U_flag) {
+ int set_csum = 0;
+ dgrp_t i;
+
+ if (sb->s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+ /*
+ * Changing the UUID requires rewriting all metadata,
+ * which can race with a mounted fs. Don't allow that.
+ */
+ if (mount_flags & EXT2_MF_MOUNTED) {
+ fputs(_("The UUID may only be "
+ "changed when the filesystem is "
+ "unmounted.\n"), stderr);
+ exit(1);
+ }
+ if (check_fsck_needed(fs))
+ exit(1);
+
+ /*
+ * Determine if the block group checksums are
+ * correct so we know whether or not to set
+ * them later on.
+ */
+ for (i = 0; i < fs->group_desc_count; i++)
+ if (!ext2fs_group_desc_csum_verify(fs, i))
+ break;
+ if (i >= fs->group_desc_count)
+ set_csum = 1;
+ }
+ if ((strcasecmp(new_UUID, "null") == 0) ||
+ (strcasecmp(new_UUID, "clear") == 0)) {
+ uuid_clear(sb->s_uuid);
+ } else if (strcasecmp(new_UUID, "time") == 0) {
+ uuid_generate_time(sb->s_uuid);
+ } else if (strcasecmp(new_UUID, "random") == 0) {
+ uuid_generate(sb->s_uuid);
+ } else if (uuid_parse(new_UUID, sb->s_uuid)) {
+ com_err(program_name, 0, "%s",
+ _("Invalid UUID format\n"));
+ rc = 1;
+ goto closefs;
+ }
+ if (set_csum) {
+ for (i = 0; i < fs->group_desc_count; i++)
+ ext2fs_group_desc_csum_set(fs, i);
+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+ }
+ ext2fs_mark_super_dirty(fs);
+ }
+ if (I_flag) {
+ if (mount_flags & EXT2_MF_MOUNTED) {
+ fputs(_("The inode size may only be "
+ "changed when the filesystem is "
+ "unmounted.\n"), stderr);
+ rc = 1;
+ goto closefs;
+ }
+ if (fs->super->s_feature_incompat &
+ EXT4_FEATURE_INCOMPAT_FLEX_BG) {
+ fputs(_("Changing the inode size not supported for "
+ "filesystems with the flex_bg\n"
+ "feature enabled.\n"),
+ stderr);
+ rc = 1;
+ goto closefs;
+ }
+ /*
+ * We want to update group descriptor also
+ * with the new free inode count
+ */
+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+ if (resize_inode(fs, new_inode_size) == 0) {
+ printf(_("Setting inode size %lu\n"),
+ new_inode_size);
+ } else {
+ printf("%s", _("Failed to change inode size\n"));
+ rc = 1;
+ goto closefs;
+ }
+ }
+
+ if (l_flag)
+ list_super(sb);
+ if (stride_set) {
+ sb->s_raid_stride = stride;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting stride size to %d\n"), stride);
+ }
+ if (stripe_width_set) {
+ sb->s_raid_stripe_width = stripe_width;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting stripe width to %d\n"), stripe_width);
+ }
+ if (ext_mount_opts) {
+ strncpy((char *)(fs->super->s_mount_opts), ext_mount_opts,
+ sizeof(fs->super->s_mount_opts));
+ fs->super->s_mount_opts[sizeof(fs->super->s_mount_opts)-1] = 0;
+ ext2fs_mark_super_dirty(fs);
+ printf(_("Setting extended default mount options to '%s'\n"),
+ ext_mount_opts);
+ free(ext_mount_opts);
+ }
+ free(device_name);
+ remove_error_table(&et_ext2_error_table);
+
+closefs:
+ if (rc) {
+ ext2fs_mmp_stop(fs);
+ exit(1);
+ }
+
+ return (ext2fs_close(fs) ? 1 : 0);
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/util.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/util.c
new file mode 100644
index 0000000..40c8858
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/util.c
@@ -0,0 +1,305 @@
+/*
+ * util.c --- helper functions used by tune2fs and mke2fs
+ *
+ * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_LINUX_MAJOR_H
+#include <linux/major.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <time.h>
+
+#include "et/com_err.h"
+#include "e2p/e2p.h"
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+#include "nls-enable.h"
+#include "blkid/blkid.h"
+#include "util.h"
+
+#ifndef HAVE_STRCASECMP
+int strcasecmp (char *s1, char *s2)
+{
+ while (*s1 && *s2) {
+ int ch1 = *s1++, ch2 = *s2++;
+ if (isupper (ch1))
+ ch1 = tolower (ch1);
+ if (isupper (ch2))
+ ch2 = tolower (ch2);
+ if (ch1 != ch2)
+ return ch1 - ch2;
+ }
+ return *s1 ? 1 : *s2 ? -1 : 0;
+}
+#endif
+
+/*
+ * Given argv[0], return the program name.
+ */
+char *get_progname(char *argv_zero)
+{
+ char *cp;
+
+ cp = strrchr(argv_zero, '/');
+ if (!cp )
+ return argv_zero;
+ else
+ return cp+1;
+}
+
+void proceed_question(void)
+{
+ char buf[256];
+ const char *short_yes = _("yY");
+
+ fflush(stdout);
+ fflush(stderr);
+ fputs(_("Proceed anyway? (y,n) "), stdout);
+ buf[0] = 0;
+ if (!fgets(buf, sizeof(buf), stdin) ||
+ strchr(short_yes, buf[0]) == 0)
+ exit(1);
+}
+
+void check_plausibility(const char *device)
+{
+ int val;
+ ext2fs_struct_stat s;
+
+ val = ext2fs_stat(device, &s);
+
+ if(val == -1) {
+ fprintf(stderr, _("Could not stat %s --- %s\n"),
+ device, error_message(errno));
+ if (errno == ENOENT)
+ fputs(_("\nThe device apparently does not exist; "
+ "did you specify it correctly?\n"), stderr);
+ exit(1);
+ }
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ /* On FreeBSD, all disk devices are character specials */
+ if (!S_ISBLK(s.st_mode) && !S_ISCHR(s.st_mode))
+#else
+ if (!S_ISBLK(s.st_mode))
+#endif
+ {
+ printf(_("%s is not a block special device.\n"), device);
+ proceed_question();
+ return;
+ }
+
+#ifdef HAVE_LINUX_MAJOR_H
+#ifndef MAJOR
+#define MAJOR(dev) ((dev)>>8)
+#define MINOR(dev) ((dev) & 0xff)
+#endif
+#ifndef SCSI_BLK_MAJOR
+#ifdef SCSI_DISK0_MAJOR
+#ifdef SCSI_DISK8_MAJOR
+#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
+ ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \
+ ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR))
+#else
+#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
+ ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
+#endif /* defined(SCSI_DISK8_MAJOR) */
+#define SCSI_BLK_MAJOR(M) (SCSI_DISK_MAJOR((M)) || (M) == SCSI_CDROM_MAJOR)
+#else
+#define SCSI_BLK_MAJOR(M) ((M) == SCSI_DISK_MAJOR || (M) == SCSI_CDROM_MAJOR)
+#endif /* defined(SCSI_DISK0_MAJOR) */
+#endif /* defined(SCSI_BLK_MAJOR) */
+ if (((MAJOR(s.st_rdev) == HD_MAJOR &&
+ MINOR(s.st_rdev)%64 == 0) ||
+ (SCSI_BLK_MAJOR(MAJOR(s.st_rdev)) &&
+ MINOR(s.st_rdev)%16 == 0))) {
+ printf(_("%s is entire device, not just one partition!\n"),
+ device);
+ proceed_question();
+ }
+#endif
+}
+
+void check_mount(const char *device, int force, const char *type)
+{
+ errcode_t retval;
+ int mount_flags;
+
+ retval = ext2fs_check_if_mounted(device, &mount_flags);
+ if (retval) {
+ com_err("ext2fs_check_if_mount", retval,
+ _("while determining whether %s is mounted."),
+ device);
+ return;
+ }
+ if (mount_flags & EXT2_MF_MOUNTED) {
+ fprintf(stderr, _("%s is mounted; "), device);
+ if (force >= 2) {
+ fputs(_("mke2fs forced anyway. Hope /etc/mtab is "
+ "incorrect.\n"), stderr);
+ return;
+ }
+ abort_mke2fs:
+ fprintf(stderr, _("will not make a %s here!\n"), type);
+ exit(1);
+ }
+ if (mount_flags & EXT2_MF_BUSY) {
+ fprintf(stderr, _("%s is apparently in use by the system; "),
+ device);
+ if (force >= 2) {
+ fputs(_("mke2fs forced anyway.\n"), stderr);
+ return;
+ }
+ goto abort_mke2fs;
+ }
+}
+
+void parse_journal_opts(const char *opts)
+{
+ char *buf, *token, *next, *p, *arg;
+ int len;
+ int journal_usage = 0;
+
+ len = strlen(opts);
+ buf = malloc(len+1);
+ if (!buf) {
+ fputs(_("Couldn't allocate memory to parse journal "
+ "options!\n"), stderr);
+ exit(1);
+ }
+ strcpy(buf, opts);
+ for (token = buf; token && *token; token = next) {
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+ arg = strchr(token, '=');
+ if (arg) {
+ *arg = 0;
+ arg++;
+ }
+#if 0
+ printf("Journal option=%s, argument=%s\n", token,
+ arg ? arg : "NONE");
+#endif
+ if (strcmp(token, "device") == 0) {
+ journal_device = blkid_get_devname(NULL, arg, NULL);
+ if (!journal_device) {
+ if (arg)
+ fprintf(stderr, _("\nCould not find "
+ "journal device matching %s\n"),
+ arg);
+ journal_usage++;
+ continue;
+ }
+ } else if (strcmp(token, "size") == 0) {
+ if (!arg) {
+ journal_usage++;
+ continue;
+ }
+ journal_size = strtoul(arg, &p, 0);
+ if (*p)
+ journal_usage++;
+ } else if (strcmp(token, "v1_superblock") == 0) {
+ journal_flags |= EXT2_MKJOURNAL_V1_SUPER;
+ continue;
+ } else
+ journal_usage++;
+ }
+ if (journal_usage) {
+ fputs(_("\nBad journal options specified.\n\n"
+ "Journal options are separated by commas, "
+ "and may take an argument which\n"
+ "\tis set off by an equals ('=') sign.\n\n"
+ "Valid journal options are:\n"
+ "\tsize=<journal size in megabytes>\n"
+ "\tdevice=<journal device>\n\n"
+ "The journal size must be between "
+ "1024 and 10240000 filesystem blocks.\n\n"), stderr);
+ free(buf);
+ exit(1);
+ }
+ free(buf);
+}
+
+/*
+ * Determine the number of journal blocks to use, either via
+ * user-specified # of megabytes, or via some intelligently selected
+ * defaults.
+ *
+ * Find a reasonable journal file size (in blocks) given the number of blocks
+ * in the filesystem. For very small filesystems, it is not reasonable to
+ * have a journal that fills more than half of the filesystem.
+ */
+unsigned int figure_journal_size(int size, ext2_filsys fs)
+{
+ int j_blocks;
+
+ j_blocks = ext2fs_default_journal_size(ext2fs_blocks_count(fs->super));
+ if (j_blocks < 0) {
+ fputs(_("\nFilesystem too small for a journal\n"), stderr);
+ return 0;
+ }
+
+ if (size > 0) {
+ j_blocks = size * 1024 / (fs->blocksize / 1024);
+ if (j_blocks < 1024 || j_blocks > 10240000) {
+ fprintf(stderr, _("\nThe requested journal "
+ "size is %d blocks; it must be\n"
+ "between 1024 and 10240000 blocks. "
+ "Aborting.\n"),
+ j_blocks);
+ exit(1);
+ }
+ if ((unsigned) j_blocks > ext2fs_free_blocks_count(fs->super) / 2) {
+ fputs(_("\nJournal size too big for filesystem.\n"),
+ stderr);
+ exit(1);
+ }
+ }
+ return j_blocks;
+}
+
+void print_check_message(int mnt, unsigned int check)
+{
+ if (mnt < 0)
+ mnt = 0;
+ if (!mnt && !check)
+ return;
+ printf(_("This filesystem will be automatically "
+ "checked every %d mounts or\n"
+ "%g days, whichever comes first. "
+ "Use tune2fs -c or -i to override.\n"),
+ mnt, ((double) check) / (3600 * 24));
+}
+
+void dump_mmp_msg(struct mmp_struct *mmp, const char *msg)
+{
+
+ if (msg)
+ printf("MMP check failed: %s\n", msg);
+ if (mmp) {
+ time_t t = mmp->mmp_time;
+
+ printf("MMP error info: last update: %s node: %s device: %s\n",
+ ctime(&t), mmp->mmp_nodename, mmp->mmp_bdevname);
+ }
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/util.h b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/util.h
new file mode 100644
index 0000000..f872c38
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/util.h
@@ -0,0 +1,27 @@
+/*
+ * util.h --- header file defining prototypes for helper functions
+ * used by tune2fs and mke2fs
+ *
+ * Copyright 2000 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+extern int journal_size;
+extern int journal_flags;
+extern char *journal_device;
+
+#ifndef HAVE_STRCASECMP
+extern int strcasecmp (char *s1, char *s2);
+#endif
+extern char *get_progname(char *argv_zero);
+extern void proceed_question(void);
+extern void check_plausibility(const char *device);
+extern void parse_journal_opts(const char *opts);
+extern void check_mount(const char *device, int force, const char *type);
+extern unsigned int figure_journal_size(int size, ext2_filsys fs);
+extern void print_check_message(int, unsigned int);
+extern void dump_mmp_msg(struct mmp_struct *mmp, const char *msg);
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidd.8.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidd.8.in
new file mode 100644
index 0000000..e65e391
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidd.8.in
@@ -0,0 +1,97 @@
+.\" -*- nroff -*-
+.\" Copyright 2007 by Theodore Ts'o. All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.TH UUIDD 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+uuidd \- UUID generation daemon
+.SH SYNOPSIS
+.B uuidd
+[
+.B \-d
+]
+[
+.B \-p
+.I pidfile
+]
+[
+.B \-s
+.I socketpath
+]
+[
+.B \-T
+.I timeout
+]
+
+.B uuidd
+[
+.B \-r
+|
+.B \-t
+]
+[
+.B \-n
+.I number
+]
+[
+.B \-s
+.I socketpath
+]
+
+.B uuidd \-k
+.SH DESCRIPTION
+The
+.B uuidd
+daemon is used by the UUID library to generate
+universally unique identifiers (UUIDs), especially time-based UUID's
+in a secure and guaranteed-unique fashion, even in the face of large
+numbers of threads trying to grab UUID's running on different CPU's.
+.SH OPTIONS
+.TP
+.B \-d
+Run
+.B uuidd
+in debugging mode. This prevents uuidd from running as a daemon.
+.TP
+.B \-k
+If a currently uuidd daemon is running, kill it.
+.TP
+.BI \-n " number"
+When issuing a test request to a running uuidd, request a bulk response
+of
+.I number
+UUID's.
+.TP
+.BI \-p " pidfile"
+Specify the pathname where the pid file should be written. By default,
+the pid file is written to /var/lib/libuuid/uuidd.pid.
+.TP
+.BI \-s " socketpath"
+Specify the pathname used for the unix-domain socket used by uuidd. By
+default, the pathname used is /var/lib/libuuid/request. This is primarily
+for debugging purposes, since the pathname is hard-coded in the libuuid
+library.
+.TP
+.B \-r
+Test uuidd by trying to connect to a running uuidd daemon and
+request it to return a random-based UUID.
+.TP
+.B \-t
+Test uuidd by trying to connect to a running uuidd daemon and
+request it to return a time-based UUID.
+.TP
+.BI \-T " timeout"
+Specify a timeout for uuidd. If specified, then uuidd will exit after
+.I timeout
+seconds of inactivity.
+.SH AUTHOR
+The
+.B uuidd
+daemon was written by Theodore Ts'o <tytso@mit.edu>.
+.SH AVAILABILITY
+.B uuidd
+is part of libuuid from the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH "SEE ALSO"
+.BR libuuid (3),
+.BR uuidgen (1)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidd.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidd.c
new file mode 100644
index 0000000..5a53138
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidd.c
@@ -0,0 +1,599 @@
+/*
+ * uuidd.c --- UUID-generation daemon
+ *
+ * Copyright (C) 2007 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _GNU_SOURCE /* for setres[ug]id() */
+
+#include "config.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <unistd.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern int getopt(int argc, char * const argv[], const char *optstring);
+extern char *optarg;
+extern int optind;
+#endif
+#include "uuid/uuid.h"
+#include "uuid/uuidd.h"
+#include "nls-enable.h"
+
+#ifdef __GNUC__
+#define CODE_ATTR(x) __attribute__(x)
+#else
+#define CODE_ATTR(x)
+#endif
+
+static void usage(const char *progname)
+{
+ fprintf(stderr, _("Usage: %s [-d] [-p pidfile] [-s socketpath] "
+ "[-T timeout]\n"), progname);
+ fprintf(stderr, _(" %s [-r|t] [-n num] [-s socketpath]\n"),
+ progname);
+ fprintf(stderr, _(" %s -k\n"), progname);
+ exit(1);
+}
+
+static void die(const char *msg)
+{
+ perror(msg);
+ exit(1);
+}
+
+static void create_daemon(void)
+{
+ pid_t pid;
+ uid_t euid;
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ exit(1);
+ } else if (pid != 0) {
+ exit(0);
+ }
+
+ close(0);
+ close(1);
+ close(2);
+ open("/dev/null", O_RDWR);
+ open("/dev/null", O_RDWR);
+ open("/dev/null", O_RDWR);
+
+ if (chdir("/")) {} /* Silence warn_unused_result warning */
+ (void) setsid();
+ euid = geteuid();
+ if (setreuid(euid, euid) < 0)
+ die("setreuid");
+}
+
+static ssize_t read_all(int fd, char *buf, size_t count)
+{
+ ssize_t ret;
+ ssize_t c = 0;
+ int tries = 0;
+
+ memset(buf, 0, count);
+ while (count > 0) {
+ ret = read(fd, buf, count);
+ if (ret <= 0) {
+ if ((errno == EAGAIN || errno == EINTR || ret == 0) &&
+ (tries++ < 5))
+ continue;
+ return c ? c : -1;
+ }
+ if (ret > 0)
+ tries = 0;
+ count -= ret;
+ buf += ret;
+ c += ret;
+ }
+ return c;
+}
+
+static int write_all(int fd, char *buf, size_t count)
+{
+ ssize_t ret;
+ int c = 0;
+
+ while (count > 0) {
+ ret = write(fd, buf, count);
+ if (ret < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ return -1;
+ }
+ count -= ret;
+ buf += ret;
+ c += ret;
+ }
+ return c;
+}
+
+static const char *cleanup_pidfile, *cleanup_socket;
+
+static void terminate_intr(int signo CODE_ATTR((unused)))
+{
+ (void) unlink(cleanup_pidfile);
+ if (cleanup_socket)
+ (void) unlink(cleanup_socket);
+ exit(0);
+}
+
+static int call_daemon(const char *socket_path, int op, char *buf,
+ int buflen, int *num, const char **err_context)
+{
+ char op_buf[8];
+ int op_len;
+ int s;
+ ssize_t ret;
+ int32_t reply_len = 0;
+ struct sockaddr_un srv_addr;
+
+ if (((op == 4) || (op == 5)) && !num) {
+ if (err_context)
+ *err_context = _("bad arguments");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ if (err_context)
+ *err_context = _("socket");
+ return -1;
+ }
+
+ srv_addr.sun_family = AF_UNIX;
+ strncpy(srv_addr.sun_path, socket_path, sizeof(srv_addr.sun_path));
+ srv_addr.sun_path[sizeof(srv_addr.sun_path)-1] = '\0';
+
+ if (connect(s, (const struct sockaddr *) &srv_addr,
+ sizeof(struct sockaddr_un)) < 0) {
+ if (err_context)
+ *err_context = _("connect");
+ close(s);
+ return -1;
+ }
+
+ if (op == 5) {
+ if ((*num)*16 > buflen-4)
+ *num = (buflen-4) / 16;
+ }
+ op_buf[0] = op;
+ op_len = 1;
+ if ((op == 4) || (op == 5)) {
+ memcpy(op_buf+1, num, sizeof(int));
+ op_len += sizeof(int);
+ }
+
+ ret = write_all(s, op_buf, op_len);
+ if (ret < op_len) {
+ if (err_context)
+ *err_context = _("write");
+ close(s);
+ return -1;
+ }
+
+ ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
+ if (ret < 0) {
+ if (err_context)
+ *err_context = _("read count");
+ close(s);
+ return -1;
+ }
+ if (reply_len < 0 || reply_len > buflen) {
+ if (err_context)
+ *err_context = _("bad response length");
+ close(s);
+ return -1;
+ }
+ ret = read_all(s, (char *) buf, reply_len);
+
+ if ((ret > 0) && (op == 4)) {
+ if (reply_len >= (int) (16+sizeof(int)))
+ memcpy(buf+16, num, sizeof(int));
+ else
+ *num = -1;
+ }
+ if ((ret > 0) && (op == 5)) {
+ if (*num >= (int) sizeof(int))
+ memcpy(buf, num, sizeof(int));
+ else
+ *num = -1;
+ }
+
+ close(s);
+
+ return ret;
+}
+
+static void server_loop(const char *socket_path, const char *pidfile_path,
+ int debug, int timeout, int quiet)
+{
+ struct sockaddr_un my_addr, from_addr;
+ struct flock fl;
+ socklen_t fromlen;
+ int32_t reply_len = 0;
+ uuid_t uu;
+ mode_t save_umask;
+ char reply_buf[1024], *cp;
+ char op, str[37];
+ int i, s, ns, len, num;
+ int fd_pidfile, ret;
+
+ fd_pidfile = open(pidfile_path, O_CREAT | O_RDWR, 0664);
+ if (fd_pidfile < 0) {
+ if (!quiet)
+ fprintf(stderr, "Failed to open/create %s: %s\n",
+ pidfile_path, strerror(errno));
+ exit(1);
+ }
+ cleanup_pidfile = pidfile_path;
+ cleanup_socket = 0;
+ signal(SIGALRM, terminate_intr);
+ alarm(30);
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ fl.l_pid = 0;
+ while (fcntl(fd_pidfile, F_SETLKW, &fl) < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ if (!quiet)
+ fprintf(stderr, "Failed to lock %s: %s\n",
+ pidfile_path, strerror(errno));
+ exit(1);
+ }
+ ret = call_daemon(socket_path, 0, reply_buf, sizeof(reply_buf), 0, 0);
+ if (ret > 0) {
+ if (!quiet)
+ printf(_("uuidd daemon already running at pid %s\n"),
+ reply_buf);
+ exit(1);
+ }
+ alarm(0);
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ if (!quiet)
+ fprintf(stderr, _("Couldn't create unix stream "
+ "socket: %s"), strerror(errno));
+ exit(1);
+ }
+
+ /*
+ * Make sure the socket isn't using fd numbers 0-2 to avoid it
+ * getting closed by create_daemon()
+ */
+ while (!debug && s <= 2) {
+ s = dup(s);
+ if (s < 0) {
+ perror("dup");
+ exit(1);
+ }
+ }
+
+ /*
+ * Create the address we will be binding to.
+ */
+ my_addr.sun_family = AF_UNIX;
+ strncpy(my_addr.sun_path, socket_path, sizeof(my_addr.sun_path));
+ my_addr.sun_path[sizeof(my_addr.sun_path)-1] = '\0';
+ (void) unlink(socket_path);
+ save_umask = umask(0);
+ if (bind(s, (const struct sockaddr *) &my_addr,
+ sizeof(struct sockaddr_un)) < 0) {
+ if (!quiet)
+ fprintf(stderr,
+ _("Couldn't bind unix socket %s: %s\n"),
+ socket_path, strerror(errno));
+ exit(1);
+ }
+ (void) umask(save_umask);
+
+ if (listen(s, 5) < 0) {
+ if (!quiet)
+ fprintf(stderr, _("Couldn't listen on unix "
+ "socket %s: %s\n"), socket_path,
+ strerror(errno));
+ exit(1);
+ }
+
+ cleanup_socket = socket_path;
+ if (!debug)
+ create_daemon();
+ signal(SIGHUP, terminate_intr);
+ signal(SIGINT, terminate_intr);
+ signal(SIGTERM, terminate_intr);
+ signal(SIGALRM, terminate_intr);
+ signal(SIGPIPE, SIG_IGN);
+
+ sprintf(reply_buf, "%8d\n", getpid());
+ if (ftruncate(fd_pidfile, 0)) {} /* Silence warn_unused_result */
+ write_all(fd_pidfile, reply_buf, strlen(reply_buf));
+ if (fd_pidfile > 1)
+ close(fd_pidfile); /* Unlock the pid file */
+
+ while (1) {
+ fromlen = sizeof(from_addr);
+ if (timeout > 0)
+ alarm(timeout);
+ ns = accept(s, (struct sockaddr *) &from_addr, &fromlen);
+ alarm(0);
+ if (ns < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ perror("accept");
+ exit(1);
+ }
+ len = read(ns, &op, 1);
+ if (len != 1) {
+ if (len < 0)
+ perror("read");
+ else
+ printf(_("Error reading from client, "
+ "len = %d\n"), len);
+ goto shutdown_socket;
+ }
+ if ((op == 4) || (op == 5)) {
+ if (read_all(ns, (char *) &num, sizeof(num)) != 4)
+ goto shutdown_socket;
+ if (debug)
+ printf(_("operation %d, incoming num = %d\n"),
+ op, num);
+ } else if (debug)
+ printf("operation %d\n", op);
+
+ switch(op) {
+ case UUIDD_OP_GETPID:
+ sprintf(reply_buf, "%d", getpid());
+ reply_len = strlen(reply_buf)+1;
+ break;
+ case UUIDD_OP_GET_MAXOP:
+ sprintf(reply_buf, "%d", UUIDD_MAX_OP);
+ reply_len = strlen(reply_buf)+1;
+ break;
+ case UUIDD_OP_TIME_UUID:
+ num = 1;
+ uuid__generate_time(uu, &num);
+ if (debug) {
+ uuid_unparse(uu, str);
+ printf(_("Generated time UUID: %s\n"), str);
+ }
+ memcpy(reply_buf, uu, sizeof(uu));
+ reply_len = sizeof(uu);
+ break;
+ case UUIDD_OP_RANDOM_UUID:
+ num = 1;
+ uuid__generate_random(uu, &num);
+ if (debug) {
+ uuid_unparse(uu, str);
+ printf(_("Generated random UUID: %s\n"), str);
+ }
+ memcpy(reply_buf, uu, sizeof(uu));
+ reply_len = sizeof(uu);
+ break;
+ case UUIDD_OP_BULK_TIME_UUID:
+ uuid__generate_time(uu, &num);
+ if (debug) {
+ uuid_unparse(uu, str);
+ printf(P_("Generated time UUID %s and "
+ "subsequent UUID\n",
+ "Generated time UUID %s and %d "
+ "subsequent UUIDs\n", num),
+ str, num);
+ }
+ memcpy(reply_buf, uu, sizeof(uu));
+ reply_len = sizeof(uu);
+ memcpy(reply_buf+reply_len, &num, sizeof(num));
+ reply_len += sizeof(num);
+ break;
+ case UUIDD_OP_BULK_RANDOM_UUID:
+ if (num < 0)
+ num = 1;
+ if (num > 1000)
+ num = 1000;
+ if (num*16 > (int) (sizeof(reply_buf)-sizeof(num)))
+ num = (sizeof(reply_buf)-sizeof(num)) / 16;
+ uuid__generate_random((unsigned char *) reply_buf +
+ sizeof(num), &num);
+ if (debug) {
+ printf(_("Generated %d UUID's:\n"), num);
+ for (i=0, cp=reply_buf+sizeof(num);
+ i < num; i++, cp+=16) {
+ uuid_unparse((unsigned char *)cp, str);
+ printf("\t%s\n", str);
+ }
+ }
+ reply_len = (num*16) + sizeof(num);
+ memcpy(reply_buf, &num, sizeof(num));
+ break;
+ default:
+ if (debug)
+ printf(_("Invalid operation %d\n"), op);
+ goto shutdown_socket;
+ }
+ write_all(ns, (char *) &reply_len, sizeof(reply_len));
+ write_all(ns, reply_buf, reply_len);
+ shutdown_socket:
+ close(ns);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ const char *socket_path = UUIDD_SOCKET_PATH;
+ const char *pidfile_path = UUIDD_PIDFILE_PATH;
+ const char *err_context;
+ char buf[1024], *cp;
+ char str[37], *tmp;
+ uuid_t uu;
+ uid_t uid;
+ gid_t gid;
+ int i, c, ret;
+ int debug = 0, do_type = 0, do_kill = 0, num = 0;
+ int timeout = 0, quiet = 0, drop_privs = 0;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+#endif
+
+ while ((c = getopt (argc, argv, "dkn:qp:s:tT:r")) != EOF) {
+ switch (c) {
+ case 'd':
+ debug++;
+ drop_privs = 1;
+ break;
+ case 'k':
+ do_kill++;
+ drop_privs = 1;
+ break;
+ case 'n':
+ num = strtol(optarg, &tmp, 0);
+ if ((num < 0) || *tmp) {
+ fprintf(stderr, _("Bad number: %s\n"), optarg);
+ exit(1);
+ }
+ break;
+ case 'p':
+ pidfile_path = optarg;
+ drop_privs = 1;
+ break;
+ case 'q':
+ quiet++;
+ break;
+ case 's':
+ socket_path = optarg;
+ drop_privs = 1;
+ break;
+ case 't':
+ do_type = UUIDD_OP_TIME_UUID;
+ drop_privs = 1;
+ break;
+ case 'T':
+ timeout = strtol(optarg, &tmp, 0);
+ if ((timeout < 0) || *tmp) {
+ fprintf(stderr, _("Bad number: %s\n"), optarg);
+ exit(1);
+ }
+ break;
+ case 'r':
+ do_type = UUIDD_OP_RANDOM_UUID;
+ drop_privs = 1;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+ uid = getuid();
+ if (uid && drop_privs) {
+ gid = getgid();
+#ifdef HAVE_SETRESGID
+ if (setresgid(gid, gid, gid) < 0)
+ die("setresgid");
+#else
+ if (setregid(gid, gid) < 0)
+ die("setregid");
+#endif
+
+#ifdef HAVE_SETRESUID
+ if (setresuid(uid, uid, uid) < 0)
+ die("setresuid");
+#else
+ if (setreuid(uid, uid) < 0)
+ die("setreuid");
+#endif
+ }
+ if (num && do_type) {
+ ret = call_daemon(socket_path, do_type+2, buf,
+ sizeof(buf), &num, &err_context);
+ if (ret < 0) {
+ printf(_("Error calling uuidd daemon (%s): %s\n"),
+ err_context, strerror(errno));
+ exit(1);
+ }
+ if (do_type == UUIDD_OP_TIME_UUID) {
+ if (ret != sizeof(uu) + sizeof(num))
+ goto unexpected_size;
+
+ uuid_unparse((unsigned char *) buf, str);
+
+ printf(P_("%s and subsequent UUID\n",
+ "%s and subsequent %d UUIDs\n", num),
+ str, num);
+ } else {
+ printf("%s", _("List of UUID's:\n"));
+ cp = buf + 4;
+ if (ret != (int) (sizeof(num) + num*sizeof(uu)))
+ goto unexpected_size;
+ for (i=0; i < num; i++, cp+=16) {
+ uuid_unparse((unsigned char *) cp, str);
+ printf("\t%s\n", str);
+ }
+ }
+ exit(0);
+ }
+ if (do_type) {
+ ret = call_daemon(socket_path, do_type, (char *) &uu,
+ sizeof(uu), 0, &err_context);
+ if (ret < 0) {
+ printf(_("Error calling uuidd daemon (%s): %s\n"),
+ err_context, strerror(errno));
+ exit(1);
+ }
+ if (ret != sizeof(uu)) {
+ unexpected_size:
+ printf(_("Unexpected reply length from server %d\n"),
+ ret);
+ exit(1);
+ }
+ uuid_unparse(uu, str);
+
+ printf("%s\n", str);
+ exit(0);
+ }
+
+ if (do_kill) {
+ ret = call_daemon(socket_path, 0, buf, sizeof(buf), 0, 0);
+ if ((ret > 0) && ((do_kill = atoi((char *) buf)) > 0)) {
+ ret = kill(do_kill, SIGTERM);
+ if (ret < 0) {
+ if (!quiet)
+ fprintf(stderr,
+ _("Couldn't kill uuidd running "
+ "at pid %d: %s\n"), do_kill,
+ strerror(errno));
+ exit(1);
+ }
+ if (!quiet)
+ printf(_("Killed uuidd running at pid %d\n"),
+ do_kill);
+ }
+ exit(0);
+ }
+
+ server_loop(socket_path, pidfile_path, debug, timeout, quiet);
+ return 0;
+}
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidd.rc b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidd.rc
new file mode 100644
index 0000000..d35645a
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidd.rc
@@ -0,0 +1,55 @@
+#! /bin/sh -e
+### BEGIN INIT INFO
+# Provides: uuidd
+# Required-Start: $time $local_fs
+# Required-Stop: $time $local_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: uuidd daemon
+# Description: Init script for the uuid generation daemon
+### END INIT INFO
+#
+# Author: "Theodore Ts'o" <tytso@mit.edu>
+#
+set -e
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+DAEMON=/usr/sbin/uuidd
+PIDFILE=/var/run/uuidd/uuidd.pid
+
+test -x $DAEMON || exit 0
+
+. /lib/lsb/init-functions
+
+case "$1" in
+ start)
+ log_daemon_msg "Starting uuid generator" "uuidd"
+ start_daemon -p $PIDFILE $DAEMON
+ log_end_msg $?
+ ;;
+ stop)
+ log_daemon_msg "Stopping uuidd generator" "uuidd"
+ killproc -p $PIDFILE $DAEMON
+ log_end_msg $?
+ ;;
+ status)
+ if pidofproc -p $PIDFILE $DAEMON >& /dev/null ; then
+ echo "$DAEMON is running";
+ exit 0;
+ else
+ echo "$DAEMON is NOT running";
+ if test -f /var/run/uuidd.pid; then exit 2; fi
+ exit 3;
+ fi
+ ;;
+ force-reload|restart)
+ $0 stop
+ $0 start
+ ;;
+ *)
+ echo "Usage: /etc/init.d/uuidd {start|stop|restart|force-reload}"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidgen.1.in b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidgen.1.in
new file mode 100644
index 0000000..985e80d
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidgen.1.in
@@ -0,0 +1,63 @@
+.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca)
+.\"
+.\" This man page was created for libuuid.so.1.1 from e2fsprogs-1.14.
+.\"
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger
+.TH UUIDGEN 1 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+uuidgen \- command\-line utility to create a new UUID value
+.SH SYNOPSIS
+.B uuidgen
+[
+.B \-r
+|
+.B \-t
+]
+.SH DESCRIPTION
+The
+.B uuidgen
+program creates (and prints)
+a new universally unique identifier (UUID) using the
+.BR libuuid (3)
+library. The new UUID can reasonably be considered unique among
+all UUIDs created on the local system,
+and among UUIDs created on other systems in the past
+and in the future.
+.PP
+There are two types of UUID's which
+.B uuidgen
+can generate: time-based UUID's and random-based UUID's. By
+default
+.B uuidgen
+will generate a random-based UUID if a high-quality random number
+generator is present. Otherwise, it will chose a time-based UUID. It
+is possible to force the generation of one of these two
+UUID types by using the
+.B \-r
+or
+.B \-t
+options.
+.SH OPTIONS
+.TP
+.B \-r
+Generate a random-based UUID. This method creates a UUID consisting mostly
+of random bits. It requires that the operating system have a high
+quality random number generator, such as
+.IR /dev/random .
+.TP
+.B \-t
+Generate a time-based UUID. This method creates a UUID based on the system
+clock plus the system's ethernet hardware address, if present.
+.SH "CONFORMING TO"
+OSF DCE 1.1
+.SH AUTHOR
+.B uuidgen
+was written by Andreas Dilger for libuuid.
+.SH AVAILABILITY
+.B uuidgen
+is part of libuuid from the e2fsprogs package and is available from
+http://e2fsprogs.sourceforge.net.
+.SH "SEE ALSO"
+.BR libuuid (3)
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidgen.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidgen.c
new file mode 100644
index 0000000..f181d19
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/misc/uuidgen.c
@@ -0,0 +1,80 @@
+/*
+ * gen_uuid.c --- generate a DCE-compatible uuid
+ *
+ * Copyright (C) 1999, Andreas Dilger and Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern int getopt(int argc, char * const argv[], const char *optstring);
+extern char *optarg;
+extern int optind;
+#endif
+#include "uuid/uuid.h"
+#include "nls-enable.h"
+
+#define DO_TYPE_TIME 1
+#define DO_TYPE_RANDOM 2
+
+static void usage(const char *progname)
+{
+ fprintf(stderr, _("Usage: %s [-r] [-t]\n"), progname);
+ exit(1);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int c;
+ int do_type = 0;
+ char str[37];
+ uuid_t uu;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "");
+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
+ textdomain(NLS_CAT_NAME);
+#endif
+
+ while ((c = getopt (argc, argv, "tr")) != EOF)
+ switch (c) {
+ case 't':
+ do_type = DO_TYPE_TIME;
+ break;
+ case 'r':
+ do_type = DO_TYPE_RANDOM;
+ break;
+ default:
+ usage(argv[0]);
+ }
+
+ switch (do_type) {
+ case DO_TYPE_TIME:
+ uuid_generate_time(uu);
+ break;
+ case DO_TYPE_RANDOM:
+ uuid_generate_random(uu);
+ break;
+ default:
+ uuid_generate(uu);
+ break;
+ }
+
+ uuid_unparse(uu, str);
+
+ printf("%s\n", str);
+
+ return 0;
+}