Whamcloud - gitweb
Many files:
authorTheodore Ts'o <tytso@mit.edu>
Sat, 26 Apr 1997 13:21:57 +0000 (13:21 +0000)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 26 Apr 1997 13:21:57 +0000 (13:21 +0000)
  Checkin of e2fsprogs 0.5b

163 files changed:
INSTALL [new file with mode: 0644]
MCONFIG [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
debugfs/.depend [new file with mode: 0644]
debugfs/Makefile [new file with mode: 0644]
debugfs/debug_cmds.ct [new file with mode: 0644]
debugfs/debugfs.8 [new file with mode: 0644]
debugfs/debugfs.c [new file with mode: 0644]
debugfs/debugfs.h [new file with mode: 0644]
debugfs/icheck.c [new file with mode: 0644]
debugfs/ncheck.c [new file with mode: 0644]
debugfs/util.c [new file with mode: 0644]
e2fsck/.depend [new file with mode: 0644]
e2fsck/CHANGES [new file with mode: 0644]
e2fsck/Makefile [new file with mode: 0644]
e2fsck/badblocks.c [new file with mode: 0644]
e2fsck/dirinfo.c [new file with mode: 0644]
e2fsck/e2fsck.8 [new file with mode: 0644]
e2fsck/e2fsck.c [new file with mode: 0644]
e2fsck/e2fsck.h [new file with mode: 0644]
e2fsck/ehandler.c [new file with mode: 0644]
e2fsck/flushb.c [new file with mode: 0644]
e2fsck/images/README [new file with mode: 0644]
e2fsck/images/baddir.img.gz [new file with mode: 0644]
e2fsck/images/badinode.img.gz [new file with mode: 0644]
e2fsck/images/badlkcnt.img.gz [new file with mode: 0644]
e2fsck/images/badroot.img.gz [new file with mode: 0644]
e2fsck/images/badtable.img.gz [new file with mode: 0644]
e2fsck/images/bbfile.img.gz [new file with mode: 0644]
e2fsck/images/bitmaps.img.gz [new file with mode: 0644]
e2fsck/images/dirlink.img.gz [new file with mode: 0644]
e2fsck/images/dup.img.gz [new file with mode: 0644]
e2fsck/images/dup2.img.gz [new file with mode: 0644]
e2fsck/images/end-bitmap.img.gz [new file with mode: 0644]
e2fsck/images/expand.img.gz [new file with mode: 0644]
e2fsck/images/lpf.img.gz [new file with mode: 0644]
e2fsck/images/mke2fs2b.img.gz [new file with mode: 0644]
e2fsck/images/noroot.img.gz [new file with mode: 0644]
e2fsck/images/test_script [new file with mode: 0644]
e2fsck/images/test_script.log [new file with mode: 0644]
e2fsck/malloc.h [new file with mode: 0644]
e2fsck/mtrace.awk [new file with mode: 0644]
e2fsck/mtrace.c [new file with mode: 0644]
e2fsck/pass1.c [new file with mode: 0644]
e2fsck/pass1b.c [new file with mode: 0644]
e2fsck/pass2.c [new file with mode: 0644]
e2fsck/pass3.c [new file with mode: 0644]
e2fsck/pass4.c [new file with mode: 0644]
e2fsck/pass5.c [new file with mode: 0644]
e2fsck/util.c [new file with mode: 0644]
lib/e2p/.depend [new file with mode: 0644]
lib/e2p/Makefile [new file with mode: 0644]
lib/e2p/e2p.h [new file with mode: 0644]
lib/e2p/fgetflags.c [new file with mode: 0644]
lib/e2p/fgetversion.c [new file with mode: 0644]
lib/e2p/fsetflags.c [new file with mode: 0644]
lib/e2p/fsetversion.c [new file with mode: 0644]
lib/e2p/getflags.c [new file with mode: 0644]
lib/e2p/getversion.c [new file with mode: 0644]
lib/e2p/iod.c [new file with mode: 0644]
lib/e2p/ls.c [new file with mode: 0644]
lib/e2p/pe.c [new file with mode: 0644]
lib/e2p/pf.c [new file with mode: 0644]
lib/e2p/ps.c [new file with mode: 0644]
lib/e2p/setflags.c [new file with mode: 0644]
lib/e2p/setversion.c [new file with mode: 0644]
lib/et/.depend [new file with mode: 0644]
lib/et/Makefile [new file with mode: 0644]
lib/et/com_err.3 [new file with mode: 0644]
lib/et/com_err.c [new file with mode: 0644]
lib/et/com_err.h [new file with mode: 0644]
lib/et/com_err.texinfo [new file with mode: 0644]
lib/et/compile_et.1 [new file with mode: 0644]
lib/et/compile_et.sh [new file with mode: 0644]
lib/et/config_script [new file with mode: 0644]
lib/et/error_message.c [new file with mode: 0644]
lib/et/error_table.h [new file with mode: 0644]
lib/et/et_c.awk [new file with mode: 0644]
lib/et/et_h.awk [new file with mode: 0644]
lib/et/et_name.c [new file with mode: 0644]
lib/et/init_et.c [new file with mode: 0644]
lib/et/internal.h [new file with mode: 0644]
lib/et/mit-sipb-copyright.h [new file with mode: 0644]
lib/et/texinfo.tex [new file with mode: 0644]
lib/et/vfprintf.c [new file with mode: 0644]
lib/ext2fs/.depend [new file with mode: 0644]
lib/ext2fs/Makefile [new file with mode: 0644]
lib/ext2fs/alloc.c [new file with mode: 0644]
lib/ext2fs/badblocks.c [new file with mode: 0644]
lib/ext2fs/bb_inode.c [new file with mode: 0644]
lib/ext2fs/bitmaps.c [new file with mode: 0644]
lib/ext2fs/bitops.c [new file with mode: 0644]
lib/ext2fs/bitops.h [new file with mode: 0644]
lib/ext2fs/block.c [new file with mode: 0644]
lib/ext2fs/closefs.c [new file with mode: 0644]
lib/ext2fs/expanddir.c [new file with mode: 0644]
lib/ext2fs/ext2_err.c [new file with mode: 0644]
lib/ext2fs/ext2_err.et [new file with mode: 0644]
lib/ext2fs/ext2_err.h [new file with mode: 0644]
lib/ext2fs/ext2fs.h [new file with mode: 0644]
lib/ext2fs/freefs.c [new file with mode: 0644]
lib/ext2fs/get_pathname.c [new file with mode: 0644]
lib/ext2fs/initialize.c [new file with mode: 0644]
lib/ext2fs/inline.c [new file with mode: 0644]
lib/ext2fs/inode.c [new file with mode: 0644]
lib/ext2fs/io.h [new file with mode: 0644]
lib/ext2fs/link.c [new file with mode: 0644]
lib/ext2fs/mkdir.c [new file with mode: 0644]
lib/ext2fs/namei.c [new file with mode: 0644]
lib/ext2fs/newdir.c [new file with mode: 0644]
lib/ext2fs/openfs.c [new file with mode: 0644]
lib/ext2fs/read_bb.c [new file with mode: 0644]
lib/ext2fs/read_bb_file.c [new file with mode: 0644]
lib/ext2fs/unix_io.c [new file with mode: 0644]
lib/ss/.depend [new file with mode: 0644]
lib/ss/Makefile [new file with mode: 0644]
lib/ss/config_script [new file with mode: 0644]
lib/ss/copyright.h [new file with mode: 0644]
lib/ss/ct_c.awk [new file with mode: 0644]
lib/ss/ct_c.sed [new file with mode: 0644]
lib/ss/data.c [new file with mode: 0644]
lib/ss/error.c [new file with mode: 0644]
lib/ss/execute_cmd.c [new file with mode: 0644]
lib/ss/help.c [new file with mode: 0644]
lib/ss/invocation.c [new file with mode: 0644]
lib/ss/list_rqs.c [new file with mode: 0644]
lib/ss/listen.c [new file with mode: 0644]
lib/ss/mit-sipb-copyright.h [new file with mode: 0644]
lib/ss/mk_cmds.sh [new file with mode: 0644]
lib/ss/pager.c [new file with mode: 0644]
lib/ss/parse.c [new file with mode: 0644]
lib/ss/prompt.c [new file with mode: 0644]
lib/ss/request_tbl.c [new file with mode: 0644]
lib/ss/requests.c [new file with mode: 0644]
lib/ss/ss.h [new file with mode: 0644]
lib/ss/ss_err.c [new file with mode: 0644]
lib/ss/ss_err.et [new file with mode: 0644]
lib/ss/ss_err.h [new file with mode: 0644]
lib/ss/ss_internal.h [new file with mode: 0644]
lib/ss/std_rqs.c [new file with mode: 0644]
lib/ss/std_rqs.ct [new file with mode: 0644]
lib/ss/test_ss.c [new file with mode: 0644]
misc/.depend [new file with mode: 0644]
misc/Makefile [new file with mode: 0644]
misc/badblocks.8 [new file with mode: 0644]
misc/badblocks.c [new file with mode: 0644]
misc/chattr.1 [new file with mode: 0644]
misc/chattr.c [new file with mode: 0644]
misc/dumpe2fs.8 [new file with mode: 0644]
misc/dumpe2fs.c [new file with mode: 0644]
misc/fsck.8 [new file with mode: 0644]
misc/fsck.c [new file with mode: 0644]
misc/fsck.h [new file with mode: 0644]
misc/lsattr.1 [new file with mode: 0644]
misc/lsattr.c [new file with mode: 0644]
misc/mke2fs.8 [new file with mode: 0644]
misc/mke2fs.c [new file with mode: 0644]
misc/mklost+found.8 [new file with mode: 0644]
misc/mklost+found.c [new file with mode: 0644]
misc/tune2fs.8 [new file with mode: 0644]
misc/tune2fs.c [new file with mode: 0644]
version.h [new file with mode: 0644]

diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..b053c6c
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,34 @@
+       To install the second extended file system management program,
+just follow the steps:
+
+1) Edit the file MCONFIG
+
+       This file contains definitions used in the various makefiles.  These
+definitions have reasonable default value but you may want to adjust them to 
+your system configuration.
+
+2) Create the dependencies files
+
+       Run `make depend' to create the dependencies files.  Note that this
+is not strictly necessary since the makefiles automagically recreates them
+if they do not exist.
+
+3) Compile the programs
+
+       Run `make' to compile the libraries and the programs.
+
+4) Install the programs
+
+       Run `make install'
+
+5) Install the include files and libraries
+
+       You can run `make install-libs' to install the include files and
+libraries.  Please note that this installation is not needed for the
+programs to work.  It is only needed if you expect to develop other
+programs using the libraries.
+
+
+       You can run `make world' as an alternative to steps 2 and 3.  This
+will create the dependencies files, compile the programs and run e2fsck on
+a test suite contained in e2fsck/images.
diff --git a/MCONFIG b/MCONFIG
new file mode 100644 (file)
index 0000000..e728fc6
--- /dev/null
+++ b/MCONFIG
@@ -0,0 +1,57 @@
+#
+# C Compiler
+#
+CC=            gcc
+
+#
+# Optimization flags
+#
+#OPT=  -g -O -fno-inline
+OPT=   -O2 -fomit-frame-pointer
+
+#
+# Warning flags
+#
+WFLAGS=                -ansi -D_POSIX_SOURCE -pedantic \
+                       -Wall -Wwrite-strings -Wpointer-arith \
+                       -Wcast-qual -Wenum-clash -Wcast-align -Wtraditional \
+                       -Wstrict-prototypes -Wmissing-prototypes \
+                       -Wnested-externs -Winline -Wshadow 
+
+#
+# Installation user and groups
+#
+BINGRP=                bin
+BINOWN=                bin
+BINMODE=       555
+INCGRP=                bin
+INCOWN=                bin
+INCMODE=       444
+LIBOWN=                bin
+LIBGRP=                bin
+LIBMODE=       444
+MANGRP=                bin
+MANOWN=                bin
+MANMODE=       444
+
+#
+# Installation programs
+#
+CHMOD=         chmod
+INSTALL=       install -c
+INSTALLBIN=    $(INSTALL) -o $(BINOWN) -g $(BINGRP) -m $(BINMODE) -s
+INSTALLINC=    $(INSTALL) -o $(INCOWN) -g $(INCGRP) -m $(INCMODE)
+INSTALLLIB=    $(INSTALL) -o $(LIBOWN) -g $(LIBGRP) -m $(LIBMODE)
+INSTALLMAN=    $(INSTALL) -o $(MANOWN) -g $(MANGRP) -m $(MANMODE)
+
+#
+# Destination directories
+#
+ETCDIR=                /etc
+INCLDIR=       /usr/include
+LIBDIR=                /usr/lib
+SBINDIR=       /sbin
+SMANDIR=       /usr/man/man8
+UMANDIR=       /usr/man/man1
+USRBINDIR=     /usr/bin
+USRSBINDIR=    /usr/sbin
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..5437a13
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,61 @@
+all: libs 
+       (cd e2fsck; $(MAKE))
+       (cd debugfs ; $(MAKE))
+       (cd misc ; $(MAKE))
+
+libs:
+       (cd lib/et; $(MAKE))
+       (cd lib/ss; $(MAKE))
+       (cd lib/ext2fs; $(MAKE))
+       (cd lib/e2p; $(MAKE))
+
+install:
+       (cd e2fsck; $(MAKE) install)
+       (cd debugfs; $(MAKE) install)
+       (cd misc ; $(MAKE) install)
+
+install-libs:
+       (cd lib/et; $(MAKE) install)
+       (cd lib/ss; $(MAKE) install)
+       (cd lib/ext2fs; $(MAKE) install)
+       (cd lib/e2p; $(MAKE) install)
+
+clean:
+       rm -f $(PROGS) \#* *.s *.o *.a *~ core MAKELOG
+       (cd lib/et; $(MAKE) clean)
+       (cd lib/ss; $(MAKE) clean)
+       (cd lib/ext2fs; $(MAKE) clean)
+       (cd lib/e2p; $(MAKE) clean)
+       (cd e2fsck; $(MAKE) clean)
+       (cd debugfs; $(MAKE) clean)
+       (cd misc ; $(MAKE) clean)
+
+really-clean: clean
+       rm -f .depend
+       (cd lib/et; $(MAKE) really-clean)
+       (cd lib/ss; $(MAKE) really-clean)
+       (cd lib/ext2fs; $(MAKE) really-clean)
+       (cd lib/e2p; $(MAKE) really-clean)
+       (cd e2fsck; $(MAKE) really-clean)
+       (cd debugfs; $(MAKE) really-clean)
+       (cd misc ; $(MAKE) really-clean)
+
+dep depend:
+       (cd lib/et; cp /dev/null .depend; $(MAKE) depend)
+       (cd lib/ss; cp /dev/null .depend; $(MAKE) depend)
+       (cd lib/ext2fs; cp /dev/null .depend; $(MAKE) depend)
+       (cd lib/e2p; cp /dev/null .depend; $(MAKE) depend)
+       (cd debugfs; cp /dev/null .depend; $(MAKE) depend)
+       (cd e2fsck; cp /dev/null .depend; $(MAKE) depend)
+       (cd misc ; cp /dev/null .depend; $(MAKE) depend)
+
+world: 
+       @date
+       $(MAKE) depend 
+       @date
+       $(MAKE) all
+       @date
+       (cd e2fsck/images; ./test_script)
+       @date
+
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..787bd20
--- /dev/null
+++ b/README
@@ -0,0 +1,42 @@
+       This is the new version (0.5) of the second extended file system
+management programs.  You need to run Linux 1.0 or above to use it since
+some programs used some ext2fs features that where not available in
+previous kernel versions.
+
+       This version contains programs written by Theodore T'so and Remy Card.
+This distribution was packaged by Ted and Remy with the help of Stephen Tweedie
+and Alexy Vovenko.
+
+       The programs written or rewritten by Ted are:
+       - libext2fs: a new library containing entries to access the control
+         structures of a second extended file system.
+       - e2fsck: a new file system checker which uses optimized routines.
+         This new checker is much more efficient and safer than the old
+         e2fsck.
+       - mke2fs: a new file system creator which uses the ext2fs library.
+       - debugfs: a file system debugger which can be used to examine and
+         change the state of a file system.  Use it with caution since it
+         can corrupt file systems if you are not careful.
+       - fsck: a new fsck front-end.  This new fsck can run multiple
+         several file system checks simultanously if they are on different
+         disks.
+
+       The programs written by Remy are:
+       - badblocks: a new bad blocks checker.  It can be run by the super
+         user to search for bad blocks on a device and can also be called
+         by e2fsck and mke2fs.
+       - dumpe2fs: a new program which displays the control structure of
+         a file system.  To understand the output of this program, one needs
+         to know the physical structure of a second extended file system.
+       - mklost+found: re-creates a lost+found directory if it has been
+         deleted.
+       - tune2fs: adjusts tunable paramaters on a file system.
+       - chattr: changes files attributes and version.
+       - lsattr: lists files attributes and version.
+
+       Manual pages are included in this package.
+
+       See the file INSTALL for installation instructions.
+
+       In case of bugs in these programs, please contact Ted <tytso@mit.edu>
+and Remy <card@masi.ibp.fr>.
diff --git a/debugfs/.depend b/debugfs/.depend
new file mode 100644 (file)
index 0000000..0788c38
--- /dev/null
@@ -0,0 +1,36 @@
+debugfs.o : debugfs.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h \
+  /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/alloca.h /usr/include/ctype.h /usr/include/string.h /usr/include/time.h \
+  /usr/include/getopt.h /usr/include/sys/stat.h /usr/include/linux/stat.h ../lib/et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../lib/ss/ss.h ../lib/ss/mit-sipb-copyright.h \
+  ../lib/ss/ss_err.h debugfs.h /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+icheck.o : icheck.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h \
+  /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/alloca.h /usr/include/ctype.h /usr/include/string.h /usr/include/time.h \
+  /usr/include/getopt.h /usr/include/sys/stat.h /usr/include/linux/stat.h debugfs.h \
+  /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+ncheck.o : ncheck.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h \
+  /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/alloca.h /usr/include/ctype.h /usr/include/string.h /usr/include/time.h \
+  /usr/include/getopt.h /usr/include/sys/stat.h /usr/include/linux/stat.h debugfs.h \
+  /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+util.o : util.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h \
+  /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/alloca.h /usr/include/ctype.h /usr/include/string.h debugfs.h /usr/include/linux/ext2_fs.h \
+  ../lib/ext2fs/ext2fs.h ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
diff --git a/debugfs/Makefile b/debugfs/Makefile
new file mode 100644 (file)
index 0000000..65b32ae
--- /dev/null
@@ -0,0 +1,42 @@
+include ../MCONFIG
+
+CFLAGS=                $(OPT) -Wall -I../lib
+LDFLAGS=       $(OPT)
+PROGS=         debugfs
+BINDIR=                $(USRSBINDIR)
+MANPAGES=      debugfs.8
+MANDIR=                $(SMANDIR)
+
+MK_CMDS=       ../lib/ss/mk_cmds
+
+DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o
+
+LIBS= -L../lib -lss -lcom_err -lext2fs
+DEPLIBS= ../lib/libss.a ../lib/libcom_err.a ../lib/libext2fs.a
+
+debugfs: $(DEBUG_OBJS) $(DEPLIBS)
+       cc $(LDFLAGS) -o debugfs $(DEBUG_OBJS) $(LIBS)
+
+debug_cmds.c debug_cmds.h: debug_cmds.ct
+       $(MK_CMDS) debug_cmds.ct
+
+install:: $(PROGS)
+       for i in $(PROGS); do \
+               $(INSTALLBIN) $$i $(BINDIR)/$$i; \
+       done
+
+install:: $(MANPAGES)
+       for i in $(MANPAGES); do \
+               $(INSTALLMAN) $$i $(MANDIR)/$$i; \
+       done
+
+clean:
+       rm -f debugfs \#* *.s *.o *.a *~ debug_cmds.c core
+
+really-clean: clean
+       rm -f debug_cmds.c .depend 
+
+dep depend .depend:
+       $(CPP) $(CFLAGS) -M *.c >.depend
+
+include .depend
diff --git a/debugfs/debug_cmds.ct b/debugfs/debug_cmds.ct
new file mode 100644 (file)
index 0000000..cd7faf1
--- /dev/null
@@ -0,0 +1,98 @@
+#
+# Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+# under the terms of the GNU Public License.
+#
+command_table debug_cmds;
+
+request do_show_debugfs_params, "Show debugfs parameters",
+       show_debugfs_params, params;
+
+request do_open_filesys, "Open a filesystem",
+       open_filesys, open;
+
+request do_close_filesys, "Close a filesystem",
+       close_filesys, close;
+
+request do_init_filesys, "Initalize a filesystem (DESTROYS DATA)",
+       init_filesys;
+
+request do_show_super_stats, "Show superblock statistics",
+       show_super_stats, stats;
+
+request do_ncheck, "Do inode->name translation",
+       ncheck;
+
+request do_icheck, "Do block->inode translation",
+       icheck;
+
+request do_chroot, "Change root directory",
+       change_root_directory, chroot;
+
+request do_change_working_dir, "Change working directory",
+       change_working_directory, cd;
+
+request do_list_dir, "List directory",
+       list_directory, ls;
+
+request do_stat, "Show inode information ",
+       show_inode_info, stat;
+
+request do_link, "Create directory link",
+       link, ln;
+
+request do_unlink, "Delete a directory link",
+       unlink;
+
+request do_mkdir, "Create a directory",
+       mkdir;
+
+request do_rmdir, "Remove a directory",
+       rmdir;
+
+request do_rm, "Remove a file (unlink and kill_file, if appropriate)",
+       rm;
+
+request do_kill_file, "Deallocate an inode and its blocks",
+       kill_file;
+
+request do_clri, "Clear an inode's contents",
+       clri;
+
+request do_freei, "Clear an inode's in-use flag",
+       freei;
+
+request do_seti, "Set an inode's in-use flag",
+       seti;
+
+request do_testi, "Test an inode's in-use flag",
+       testi;
+
+request do_freeb, "Clear a block's in-use flag",
+       freeb;
+
+request do_setb, "Set a block's in-use flag",
+       setb;
+
+request do_testb, "Test a block's in-use flag",
+       testb;
+
+request do_modify_inode, "Modify an inode by structure",
+       modify_inode, mi;
+
+request do_find_free_block, "Find free block(s)",
+       find_free_block, ffb;
+
+request do_find_free_inode, "Find free inode(s)",
+       find_free_inode, ffi;
+
+request        do_print_working_directory, "Print current working directory",
+       print_working_directory, pwd; 
+
+request        do_expand_dir, "Expand directory",
+       expand_dir, expand;
+
+end;
+
+
+
+
diff --git a/debugfs/debugfs.8 b/debugfs/debugfs.8
new file mode 100644 (file)
index 0000000..3d03e6b
--- /dev/null
@@ -0,0 +1,133 @@
+.\" -*- nroff -*-
+.TH DEBUGFS 8 "March 1994" "Version 0.4b"
+.SH NAME
+debugfs \- ext2 file system debugger
+.SH SYNOPSIS
+.B debugfs
+[
+[
+.B \-w
+]
+device
+]
+.SH DESCRIPTION
+.B debugfs
+is a file system debugger. It can be used to examine and change the
+state of an ext2 file system.
+.br
+.I device
+is the special file corresponding to the device containing the ext2
+file system (e.g /dev/hdXX).
+.SH OPTIONS
+.TP
+.I -w
+Specify that the file system should be open in read-write mode. Without this
+option, the file system is open in read-only mode.
+.SH COMMANDS
+.B debugfs
+is an interactive debugger. It understands a number of commands.
+.TP
+.I cd file
+.TP
+.I chroot file
+.TP
+.I close
+Close the currently open file system.
+.TP
+.I clri file
+Clear the contents of the inode corresponding to
+.I file
+.TP
+.I expand_dir, file
+Expand a directory.
+.TP
+.I find_free_block [goal]
+Find the first free block, starting from
+.I goal
+and allocates it.
+.TP
+.I find_free_inode [dir [mode]]
+Find a free inode and allocates it.
+.TP
+.I freeb block
+Mark the block as not allocated.
+.TP
+.I freei file
+Free the inode corresponding to
+.I file
+.TP
+.I help
+.TP
+.I iname inode
+Print the file name corresponding to
+.I inode
+(currently not implemented).
+.TP
+.I initialize device blocksize
+Create an ext2 file system on
+.I device
+.TP
+.I kill_file file
+Remove a file and deallocates its blocks.
+.TP
+.I ln source_file dest_file
+Create a link.
+.TP
+.I ls [pathname]
+Emulate the
+.BR ls (1)
+command.
+.TP
+.I modify_inode file
+Modify the contents of the inode corresponding to
+.I file
+.TP
+.I mkdir file
+Make a directory.
+.TP
+.I open [-w] device
+Open a file system.
+.TP
+.I pwd
+.TP
+.I quit
+Quit
+.B debugfs
+.TP
+.I rm file
+Remove a file.
+.TP
+.I rmdir file
+Remove a directory.
+.TP
+.I setb block
+Mark the block as allocated.
+.TP
+.I seti file
+Mark in use the inode corresponding to
+.I file
+.TP
+.I show_super_stats
+List the contents of the super block.
+.TP
+.I stat file
+Dump the contents of the inode corresponding to
+.I file
+.TP
+.I testb block
+Test if the block is marked as allocated.
+.TP
+.I testi file
+Test if the inode correponding to
+.I file
+is marked as allocated.
+.TP
+.I unlink file
+Remove a link.
+.SH AUTHOR
+.B debugfs
+has been written by Theodore T'so <tytso@mit.edu>.
+.SH SEE ALSO
+.BR dumpe2fs (8),
+.BR e2fsck (8),
+.BR mke2fs (8)
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
new file mode 100644 (file)
index 0000000..b92746a
--- /dev/null
@@ -0,0 +1,1142 @@
+/*
+ * debugfs.c --- a program which allows you to attach an ext2fs
+ * filesystem and play with it.
+ *
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ * 
+ * Modifications by Robert Sanders <gt8134b@prism.gatech.edu>
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "et/com_err.h"
+#include "ss/ss.h"
+#include "debugfs.h"
+
+extern ss_request_table debug_cmds;
+
+ext2_filsys fs = NULL;
+ino_t  root, cwd;
+
+void open_filesystem(char *device, int open_flags)
+{
+       int     retval;
+       
+       retval = ext2fs_open(device, open_flags, 0, 0, unix_io_manager, &fs);
+       if (retval) {
+               com_err(device, retval, "while opening filesystem");
+               fs = NULL;
+               return;
+       }
+       retval = ext2fs_read_inode_bitmap(fs);
+       if (retval) {
+               com_err(device, retval, "while reading inode bitmap");
+               goto errout;
+       }
+       retval = ext2fs_read_block_bitmap(fs);
+       if (retval) {
+               com_err(device, retval, "while reading block bitmap");
+               goto errout;
+       }
+       root = cwd = EXT2_ROOT_INO;
+       return;
+
+errout:
+       retval = ext2fs_close(fs);
+       if (retval)
+               com_err(device, retval, "while trying to close filesystem");
+       fs = NULL;
+}
+
+void do_open_filesys(int argc, char **argv)
+{
+       char    *usage = "Usage: open [-w] <device>";
+       char    c;
+       int open_flags = 0;
+       
+       optind = 0;
+       while ((c = getopt (argc, argv, "w")) != EOF) {
+               switch (c) {
+               case 'w':
+                       open_flags = EXT2_FLAG_RW;
+                       break;
+               default:
+                       com_err(argv[0], 0, usage);
+                       return;
+               }
+       }
+       if (optind != argc-1) {
+               com_err(argv[0], 0, usage);
+               return;
+       }
+       if (check_fs_not_open(argv[0]))
+               return;
+       open_filesystem(argv[optind], open_flags);
+}
+
+void close_filesystem()
+{
+       int     retval;
+       
+       if (fs->flags & EXT2_FLAG_IB_DIRTY) {
+               retval = ext2fs_write_inode_bitmap(fs);
+               if (retval)
+                       com_err("ext2fs_write_inode_bitmap", retval, "");
+       }
+       if (fs->flags & EXT2_FLAG_BB_DIRTY) {
+               retval = ext2fs_write_block_bitmap(fs);
+               if (retval)
+                       com_err("ext2fs_write_block_bitmap", retval, "");
+       }
+       retval = ext2fs_close(fs);
+       if (retval)
+               com_err("ext2fs_close", retval, "");
+       fs = NULL;
+       return;
+}
+
+void do_close_filesys(int argc, char **argv)
+{
+       if (argc > 1) {
+               com_err(argv[0], 0, "Usage: close_filesys");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       close_filesystem();
+}
+
+void do_init_filesys(int argc, char **argv)
+{
+       char    *usage = "Usage: initialize <device> <blocksize>";
+       struct ext2_super_block param;
+       errcode_t       retval;
+       char            *tmp;
+       
+       if (argc != 3) {
+               com_err(argv[0], 0, usage);
+               return;
+       }
+       if (check_fs_not_open(argv[0]))
+               return;
+
+       memset(&param, 0, sizeof(struct ext2_super_block));
+       param.s_blocks_count = strtoul(argv[2], &tmp, 0);
+       if (*tmp) {
+               com_err(argv[0], 0, "Bad blocks count - %s", argv[2]);
+               return;
+       }
+       retval = ext2fs_initialize(argv[1], 0, &param, unix_io_manager, &fs);
+       if (retval) {
+               com_err(argv[1], retval, "while initializing filesystem");
+               fs = NULL;
+               return;
+       }
+       root = cwd = EXT2_ROOT_INO;
+       return;
+}
+
+void do_show_super_stats(int argc, char *argv[])
+{
+       int     i;
+       FILE    *out;
+
+       if (argc > 1) {
+               com_err(argv[0], 0, "Usage: show_super");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       out = open_pager();
+       fprintf(out, "Filesystem is read-%s\n", fs->flags & EXT2_FLAG_RW ?
+               "write" : "only");
+       fprintf(out, "Last mount time = %s", ctime(&fs->super->s_mtime));
+       fprintf(out, "Last write time = %s", ctime(&fs->super->s_wtime));
+       fprintf(out, "Mount counts = %d (maximal = %d)\n",
+               fs->super->s_mnt_count, fs->super->s_max_mnt_count);
+       fprintf(out, "Superblock size = %d\n", sizeof(struct ext2_super_block));
+       fprintf(out, "Block size = %d, fragment size = %d\n",
+               EXT2_BLOCK_SIZE(fs->super), EXT2_FRAG_SIZE(fs->super));
+       fprintf(out, "%ld inodes, %ld free\n", fs->super->s_inodes_count,
+               fs->super->s_free_inodes_count);
+       fprintf(out, "%ld blocks, %ld free, %ld reserved, first block = %ld\n",
+               fs->super->s_blocks_count, fs->super->s_free_blocks_count,
+               fs->super->s_r_blocks_count, fs->super->s_first_data_block);
+       fprintf(out, "%ld blocks per group\n", fs->super->s_blocks_per_group);
+       fprintf(out, "%ld fragments per group\n", fs->super->s_frags_per_group);
+       fprintf(out, "%ld inodes per group\n", EXT2_INODES_PER_GROUP(fs->super));
+       fprintf(out, "%d inodes per block\n", EXT2_INODES_PER_BLOCK(fs->super));
+       fprintf(out, "%ld group%s (%ld descriptors block%s)\n",
+               fs->group_desc_count, (fs->group_desc_count != 1) ? "s" : "",
+               fs->desc_blocks, (fs->desc_blocks != 1) ? "s" : "");
+       for (i = 0; i < fs->group_desc_count; i++)
+               fprintf(out, " Group %2d: block bitmap at %ld, "
+                       "inode bitmap at %ld, "
+                       "inode table at %ld\n"
+                       "           %d free block%s, "
+                       "%d free inode%s, "
+                       "%d used director%s\n",
+                       i, fs->group_desc[i].bg_block_bitmap,
+                       fs->group_desc[i].bg_inode_bitmap,
+                       fs->group_desc[i].bg_inode_table,
+                       fs->group_desc[i].bg_free_blocks_count,
+                       fs->group_desc[i].bg_free_blocks_count != 1 ? "s" : "",
+                       fs->group_desc[i].bg_free_inodes_count,
+                       fs->group_desc[i].bg_free_inodes_count != 1 ? "s" : "",
+                       fs->group_desc[i].bg_used_dirs_count,
+                       fs->group_desc[i].bg_used_dirs_count != 1 ? "ies" : "y");
+       close_pager(out);
+}
+
+struct list_blocks_struct {
+       FILE    *f;
+       int     total;
+};
+
+int list_blocks_proc(ext2_filsys fs, blk_t *blocknr, int blockcnt, void *private)
+{
+       struct list_blocks_struct *lb = (struct list_blocks_struct *) private;
+
+       fprintf(lb->f, "%ld ", *blocknr);
+       lb->total++;
+       return 0;
+}
+
+
+void dump_blocks(FILE *f, ino_t inode)
+{
+       struct list_blocks_struct lb;
+
+       fprintf(f, "BLOCKS:\n");
+       lb.total = 0;
+       lb.f = f;
+       ext2fs_block_iterate(fs,inode,0,NULL,list_blocks_proc,(void *)&lb);
+       if (lb.total)
+               fprintf(f, "\nTOTAL: %d\n", lb.total);
+       fprintf(f,"\n");
+}
+
+
+void dump_inode(ino_t inode_num, struct ext2_inode inode)
+{
+       char *i_type;
+       FILE    *out;
+       
+       out = open_pager();
+       if (S_ISDIR(inode.i_mode)) i_type = "directory";
+       else if (S_ISREG(inode.i_mode)) i_type = "regular";
+       else if (S_ISLNK(inode.i_mode)) i_type = "symlink";
+       else if (S_ISBLK(inode.i_mode)) i_type = "block special";
+       else if (S_ISCHR(inode.i_mode)) i_type = "character special";
+       else if (S_ISFIFO(inode.i_mode)) i_type = "FIFO";
+       else if (S_ISSOCK(inode.i_mode)) i_type = "socket";
+       else i_type = "bad type";
+       fprintf(out, "Inode: %ld   Type: %s    ", inode_num, i_type);
+       fprintf(out, "Mode:  %04o   Flags: 0x%lx   Version: %ld\n",
+               inode.i_mode & 0777, inode.i_flags, inode.i_version);
+       fprintf(out, "User: %5d   Group: %5d   Size: %ld\n",  
+               inode.i_uid, inode.i_gid, inode.i_size);
+       fprintf(out, "File ACL: %ld    Directory ACL: %ld\n",
+               inode.i_file_acl, inode.i_dir_acl);
+       fprintf(out, "Links: %d   Blockcount: %ld\n", inode.i_links_count,
+               inode.i_blocks);
+       fprintf(out, "Fragment:  Address: %ld    Number: %d    Size: %d\n",
+               inode.i_faddr, inode.i_frag, inode.i_fsize);
+       fprintf(out, "ctime: 0x%08lx -- %s", inode.i_ctime,
+               ctime(&inode.i_ctime));
+       fprintf(out, "atime: 0x%08lx -- %s", inode.i_atime,
+               ctime(&inode.i_atime));
+       fprintf(out, "mtime: 0x%08lx -- %s", inode.i_mtime,
+               ctime(&inode.i_mtime));
+       if (inode.i_dtime) 
+         fprintf(out, "dtime: 0x%08lx -- %s", inode.i_dtime,
+                 ctime(&inode.i_dtime));
+       if (S_ISLNK(inode.i_mode) && inode.i_blocks == 0)
+               fprintf(out, "Fast_link_dest: %s\n", (char *)inode.i_block);
+       else
+               dump_blocks(out, inode_num);
+       close_pager(out);
+}
+
+
+void do_stat(int argc, char *argv[])
+{
+       ino_t   inode;
+       struct ext2_inode inode_buf;
+       int retval;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: stat <file>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       inode = string_to_inode(argv[1]);
+       if (!inode) 
+               return;
+
+       retval = ext2fs_read_inode(fs,inode,&inode_buf);
+       if (retval) 
+         {
+           com_err(argv[0], 0, "Reading inode");
+           return;
+         }
+
+       dump_inode(inode,inode_buf);
+       return;
+}
+
+void do_chroot(int argc, char *argv[])
+{
+       ino_t inode;
+       int retval;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: chroot <file>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       inode = string_to_inode(argv[1]);
+       if (!inode) 
+               return;
+
+       retval = ext2fs_check_directory(fs, inode);
+       if (retval)  {
+               com_err(argv[1], retval, "");
+               return;
+       }
+       root = inode;
+}
+
+void do_clri(int argc, char *argv[])
+{
+       ino_t inode;
+       int retval;
+       struct ext2_inode inode_buf;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: clri <file>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       if (!(fs->flags & EXT2_FLAG_RW)) {
+               com_err(argv[0], 0, "Filesystem opened read/only");
+               return;
+       }
+       inode = string_to_inode(argv[1]);
+       if (!inode) 
+               return;
+
+       retval = ext2fs_read_inode(fs, inode, &inode_buf);
+       if (retval) {
+               com_err(argv[0], 0, "while trying to read inode %d", inode);
+               return;
+       }
+       memset(&inode_buf, 0, sizeof(inode_buf));
+       retval = ext2fs_write_inode(fs, inode, &inode_buf);
+       if (retval) {
+               com_err(argv[0], retval, "while trying to write inode %d",
+                       inode);
+               return;
+       }
+}
+
+void do_freei(int argc, char *argv[])
+{
+       ino_t inode;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: freei <file>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       if (!(fs->flags & EXT2_FLAG_RW)) {
+               com_err(argv[0], 0, "Filesystem opened read/only");
+               return;
+       }
+       inode = string_to_inode(argv[1]);
+       if (!inode) 
+               return;
+
+       if (!ext2fs_test_inode_bitmap(fs,fs->inode_map,inode))
+               com_err(argv[0], 0, "Warning: inode already clear");
+       ext2fs_unmark_inode_bitmap(fs,fs->inode_map,inode);
+       ext2fs_mark_ib_dirty(fs);
+}
+
+void do_seti(int argc, char *argv[])
+{
+       ino_t inode;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: seti <file>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       if (!(fs->flags & EXT2_FLAG_RW)) {
+               com_err(argv[0], 0, "Filesystem opened read/only");
+               return;
+       }
+       inode = string_to_inode(argv[1]);
+       if (!inode) 
+               return;
+
+       if (ext2fs_test_inode_bitmap(fs,fs->inode_map,inode))
+               com_err(argv[0], 0, "Warning: inode already set");
+       ext2fs_mark_inode_bitmap(fs,fs->inode_map,inode);
+       ext2fs_mark_ib_dirty(fs);
+}
+
+void do_testi(int argc, char *argv[])
+{
+       ino_t inode;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: testi <file>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       inode = string_to_inode(argv[1]);
+       if (!inode) 
+               return;
+
+       if (ext2fs_test_inode_bitmap(fs,fs->inode_map,inode))
+               printf("Inode %ld is marked in use\n", inode);
+       else
+               printf("Inode %ld is not in use\n", inode);
+}
+
+
+void do_freeb(int argc, char *argv[])
+{
+       blk_t block;
+       char *tmp;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: freeb <block>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       if (!(fs->flags & EXT2_FLAG_RW)) {
+               com_err(argv[0], 0, "Filesystem opened read/only");
+               return;
+       }
+       block = strtoul(argv[1], &tmp, 0);
+       if (!block || *tmp) {
+               com_err(argv[0], 0, "No block 0");
+               return;
+       } 
+       if (!ext2fs_test_block_bitmap(fs,fs->block_map,block))
+               com_err(argv[0], 0, "Warning: block already clear");
+       ext2fs_unmark_block_bitmap(fs,fs->block_map,block);
+       ext2fs_mark_bb_dirty(fs);
+}
+
+void do_setb(int argc, char *argv[])
+{
+       blk_t block;
+       char *tmp;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: setb <block>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       if (!(fs->flags & EXT2_FLAG_RW)) {
+               com_err(argv[0], 0, "Filesystem opened read/only");
+               return;
+       }
+       block = strtoul(argv[1], &tmp, 0);
+       if (!block || *tmp) {
+               com_err(argv[0], 0, "No block 0");
+               return;
+       } 
+       if (ext2fs_test_block_bitmap(fs,fs->block_map,block))
+               com_err(argv[0], 0, "Warning: block already set");
+       ext2fs_mark_block_bitmap(fs,fs->block_map,block);
+       ext2fs_mark_bb_dirty(fs);
+}
+
+void do_testb(int argc, char *argv[])
+{
+       blk_t block;
+       char *tmp;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: testb <block>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       block = strtoul(argv[1], &tmp, 0);
+       if (!block || *tmp) {
+               com_err(argv[0], 0, "No block 0");
+               return;
+       } 
+       if (ext2fs_test_block_bitmap(fs,fs->block_map,block))
+               printf("Block %ld marked in use\n", block);
+       else printf("Block %ld not in use\n", block);
+}
+
+void modify_char(char *com, char *prompt, char *format, u_char *val)
+{
+       char buf[200];
+       u_char v;
+       char *tmp;
+
+       sprintf(buf, format, *val);
+       printf("%30s    [%s] ", prompt, buf);
+       fgets(buf, sizeof(buf), stdin);
+       if (buf[strlen (buf) - 1] == '\n')
+               buf[strlen (buf) - 1] = '\0';
+       if (!buf[0])
+               return;
+       v = strtol(buf, &tmp, 0);
+       if (*tmp)
+               com_err(com, 0, "Bad value - %s", buf);
+       else
+               *val = v;
+}
+
+void modify_short(char *com, char *prompt, char *format, u_short *val)
+{
+       char buf[200];
+       u_short v;
+       char *tmp;
+
+       sprintf(buf, format, *val);
+       printf("%30s    [%s] ", prompt, buf);
+       fgets(buf, sizeof(buf), stdin);
+       if (buf[strlen (buf) - 1] == '\n')
+               buf[strlen (buf) - 1] = '\0';
+       if (!buf[0])
+               return;
+       v = strtol(buf, &tmp, 0);
+       if (*tmp)
+               com_err(com, 0, "Bad value - %s", buf);
+       else
+               *val = v;
+}
+
+void modify_long(char *com, char *prompt, char *format, u_long *val)
+{
+       char buf[200];
+       u_long v;
+       char *tmp;
+
+       sprintf(buf, format, *val);
+       printf("%30s    [%s] ", prompt, buf);
+       fgets(buf, sizeof(buf), stdin);
+       if (buf[strlen (buf) - 1] == '\n')
+               buf[strlen (buf) - 1] = '\0';
+       if (!buf[0])
+               return;
+       v = strtol(buf, &tmp, 0);
+       if (*tmp)
+               com_err(com, 0, "Bad value - %s", buf);
+       else
+               *val = v;
+}
+
+
+void do_modify_inode(int argc, char *argv[])
+{
+       struct ext2_inode inode;
+       ino_t inode_num;
+       int i;
+       errcode_t       retval;
+       char    buf[80];
+       char *hex_format = "0x%x";
+       char *octal_format = "0%o";
+       char *decimal_format = "%d";
+       
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: modify_inode <file>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       if (!(fs->flags & EXT2_FLAG_RW)) {
+               com_err(argv[0], 0, "Filesystem opened read/only");
+               return;
+       }
+
+       inode_num = string_to_inode(argv[1]);
+       if (!inode_num) 
+               return;
+
+       retval = ext2fs_read_inode(fs, inode_num, &inode);
+       if (retval) {
+               com_err(argv[1], retval, "while trying to read inode %d",
+                       inode_num);
+               return;
+       }
+       
+       modify_short(argv[0], "Mode", octal_format, &inode.i_mode);
+       modify_short(argv[0], "User ID", decimal_format, &inode.i_uid);
+       modify_short(argv[0], "Group ID", decimal_format, &inode.i_gid);
+       modify_long(argv[0], "Size", decimal_format, &inode.i_size);
+       modify_long(argv[0], "Creation time", decimal_format, &inode.i_ctime);
+       modify_long(argv[0], "Modification time", decimal_format, &inode.i_mtime);
+       modify_long(argv[0], "Access time", decimal_format, &inode.i_atime);
+       modify_long(argv[0], "Deletion time", decimal_format, &inode.i_dtime);
+       modify_short(argv[0], "Link count", decimal_format, &inode.i_links_count);
+       modify_long(argv[0], "Block count", decimal_format, &inode.i_blocks);
+       modify_long(argv[0], "File flags", hex_format, &inode.i_flags);
+       modify_long(argv[0], "Reserved1", decimal_format, &inode.i_reserved1);
+       modify_long(argv[0], "File acl", decimal_format, &inode.i_file_acl);
+       modify_long(argv[0], "Directory acl", decimal_format, &inode.i_dir_acl);
+       modify_long(argv[0], "Fragment address", decimal_format, &inode.i_faddr);
+       modify_char(argv[0], "Fragment number", decimal_format, &inode.i_frag);
+       modify_char(argv[0], "Fragment size", decimal_format, &inode.i_fsize);
+       for (i=0;  i < EXT2_NDIR_BLOCKS; i++) {
+               sprintf(buf, "Direct Block #%d", i);
+               modify_long(argv[0], buf, decimal_format, &inode.i_block[i]);
+       }
+       modify_long(argv[0], "Indirect Block", decimal_format,
+                   &inode.i_block[EXT2_IND_BLOCK]);    
+       modify_long(argv[0], "Double Indirect Block", decimal_format,
+                   &inode.i_block[EXT2_DIND_BLOCK]);
+       modify_long(argv[0], "Triple Indirect Block", decimal_format,
+                   &inode.i_block[EXT2_TIND_BLOCK]);
+       retval = ext2fs_write_inode(fs, inode_num, &inode);
+       if (retval) {
+               com_err(argv[1], retval, "while trying to write inode %d",
+                       inode_num);
+               return;
+       }
+}
+
+/*
+ * list directory
+ */
+
+struct list_dir_struct {
+       FILE    *f;
+       int     col;
+};
+
+int list_dir_proc(struct ext2_dir_entry *dirent,
+                 int   offset,
+                 int   blocksize,
+                 char  *buf,
+                 void  *private)
+{
+       char    name[EXT2_NAME_LEN];
+       char    tmp[EXT2_NAME_LEN + 16];
+
+       struct list_dir_struct *ls = (struct list_dir_struct *) private;
+       int     thislen;
+
+       thislen = (dirent->name_len < EXT2_NAME_LEN) ? dirent->name_len :
+               EXT2_NAME_LEN;
+       strncpy(name, dirent->name, thislen);
+       name[thislen] = '\0';
+
+       sprintf(tmp, "%ld (%d) %s   ", dirent->inode, dirent->rec_len, name);
+       thislen = strlen(tmp);
+
+       if (ls->col + thislen > 80) {
+               fprintf(ls->f, "\n");
+               ls->col = 0;
+       }
+       fprintf(ls->f, "%s", tmp);
+       ls->col += thislen;
+               
+       return 0;
+}
+
+void do_list_dir(int argc, char *argv[])
+{
+       ino_t   inode;
+       int     retval;
+       struct list_dir_struct ls;
+       
+       if (argc > 2) {
+               com_err(argv[0], 0, "Usage: list_dir [pathname]");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       if (argc == 2)
+               inode = string_to_inode(argv[1]);
+       else
+               inode = cwd;
+       if (!inode)
+               return;
+
+       ls.f = open_pager();
+       ls.col = 0;
+       retval = ext2fs_dir_iterate(fs, inode, DIRENT_FLAG_INCLUDE_EMPTY,
+                                   0, list_dir_proc, &ls);
+       fprintf(ls.f, "\n");
+       close_pager(ls.f);
+       if (retval)
+               com_err(argv[1], retval, "");
+
+       return;
+}
+
+void do_change_working_dir(int argc, char *argv[])
+{
+       ino_t   inode;
+       int     retval;
+       
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: cd <file>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       inode = string_to_inode(argv[1]);
+       if (!inode) 
+               return;
+
+       retval = ext2fs_check_directory(fs, inode);
+       if (retval) {
+               com_err(argv[1], retval, "");
+               return;
+       }
+       cwd = inode;
+       return;
+}
+
+void do_iname(int argc, char *argv[])
+{
+       ino_t   inode;
+       
+       if (argc > 2) {
+               com_err(argv[0], 0, "Usage: iname <inode>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       inode = strtoul(argv[1], NULL, 0);
+       com_err(argv[0],0,"Function unimplemented");
+       return;
+}
+
+void do_print_working_directory(int argc, char *argv[])
+{
+       int     retval;
+       char    *pathname = NULL;
+       
+       if (argc > 1) {
+               com_err(argv[0], 0, "Usage: print_working_directory");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       retval = ext2fs_get_pathname(fs, cwd, 0, &pathname);
+       if (retval) {
+               com_err(argv[0], retval,
+                       "while trying to get pathname of cwd");
+       }
+       printf("[pwd]   INODE: %6ld  PATH: %s\n", cwd, pathname);
+       free(pathname);
+       retval = ext2fs_get_pathname(fs, root, 0, &pathname);
+       if (retval) {
+               com_err(argv[0], retval,
+                       "while trying to get pathname of root");
+       }
+       printf("[root]  INODE: %6ld  PATH: %s\n", root, pathname);
+       free(pathname);
+       return;
+}
+
+
+void make_link(char *sourcename, char *destname)
+{
+       ino_t   inode;
+       int     retval;
+       ino_t   dir;
+       char    *dest, *cp, *basename;
+
+       /*
+        * Get the source inode
+        */
+       inode = string_to_inode(sourcename);
+       if (!inode)
+               return;
+       basename = strrchr(sourcename, '/');
+       if (basename)
+               basename++;
+       else
+               basename = sourcename;
+       /*
+        * Figure out the destination.  First see if it exists and is
+        * a directory.  
+        */
+       if (! (retval=ext2fs_namei(fs, root, cwd, destname, &dir)))
+               dest = basename;
+       else {
+               /*
+                * OK, it doesn't exist.  See if it is
+                * '<dir>/basename' or 'basename'
+                */
+               cp = strrchr(destname, '/');
+               if (cp) {
+                       *cp = 0;
+                       dir = string_to_inode(destname);
+                       if (!dir)
+                               return;
+                       dest = cp+1;
+               } else {
+                       dir = cwd;
+                       dest = destname;
+               }
+       }
+       
+       retval = ext2fs_link(fs, dir, dest, inode, 0);
+       if (retval)
+               com_err("make_link", retval, "");
+       return;
+}
+
+
+void do_link(int argc, char *argv[])
+{
+       if (argc != 3) {
+               com_err(argv[0], 0, "Usage: link <source_file> <dest_name>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       make_link(argv[1], argv[2]);
+}
+
+
+void unlink_file_by_name(char *filename)
+{
+       int     retval;
+       ino_t   dir;
+       char    *basename;
+       
+       basename = strrchr(filename, '/');
+       if (basename) {
+               *basename++ = '0';
+               dir = string_to_inode(filename);
+               if (!dir)
+                       return;
+       } else {
+               dir = cwd;
+               basename = filename;
+       }
+       retval = ext2fs_unlink(fs, dir, basename, 0, 0);
+       if (retval)
+               com_err("unlink_file_by_name", retval, "");
+       return;
+}
+
+void do_unlink(int argc, char *argv[])
+{
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: unlink <pathname>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       unlink_file_by_name(argv[1]);
+}
+
+void do_find_free_block(int argc, char *argv[])
+{
+       blk_t   free_blk, goal;
+       errcode_t       retval;
+       char            *tmp;
+       
+       if (argc > 2 || *argv[1] == '?') {
+               com_err(argv[0], 0, "Usage: find_free_block <goal>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       if (argc > 1) {
+               goal = strtol(argv[1], &tmp, 0);
+               if (*tmp) {
+                       com_err(argv[0], 0, "Bad goal - %s", argv[1]);
+                       return;
+               }
+       }
+       else
+               goal = fs->super->s_first_data_block;
+
+       retval = ext2fs_new_block(fs, goal, 0, &free_blk);
+       if (retval)
+               com_err("ext2fs_new_block", retval, "");
+       else
+               printf("Free block found: %ld\n", free_blk);
+
+}
+
+void do_find_free_inode(int argc, char *argv[])
+{
+       ino_t   free_inode, dir;
+       int     mode;
+       int     retval;
+       char    *tmp;
+       
+       if (argc > 3 || *argv[1] == '?') {
+               com_err(argv[0], 0, "Usage: find_free_inode <dir> <mode>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       if (argc > 1) {
+               dir = strtol(argv[1], &tmp, 0);
+               if (*tmp) {
+                       com_err(argv[0], 0, "Bad dir - %s", argv[1]);
+                       return;
+               }
+       }
+       else
+               dir = root;
+       if (argc > 2) {
+               mode = strtol(argv[2], &tmp, 0);
+               if (*tmp) {
+                       com_err(argv[0], 0, "Bad mode - %s", argv[2]);
+                       return;
+               }
+       }
+       else
+               mode = 010755;
+
+       retval = ext2fs_new_inode(fs, dir, mode, 0, &free_inode);
+       if (retval)
+               com_err("ext2fs_new_inode", retval, "");
+       else
+               printf("Free inode found: %ld\n", free_inode);
+}
+
+/*
+ * Doesn't change directories count --->  add this later
+ */
+
+void do_mkdir(int argc, char *argv[])
+{
+       char    *cp;
+       ino_t   parent;
+       char    *name;
+       errcode_t retval;
+
+       if (check_fs_open(argv[0]))
+               return;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: mkdir <file>");
+               return;
+       }
+
+       cp = strrchr(argv[1], '/');
+       if (cp) {
+               *cp = 0;
+               parent = string_to_inode(argv[1]);
+               if (!parent) {
+                       com_err(argv[1], ENOENT, "");
+                       return;
+               }
+               name = cp+1;
+       } else {
+               parent = cwd;
+               name = argv[1];
+       }
+
+
+       retval = ext2fs_mkdir(fs, parent, 0, name);
+       if (retval) {
+               com_err("ext2fs_mkdir", retval, "");
+               return;
+       }
+
+}
+
+void do_rmdir(int argc, char *argv[])
+{
+       printf("Unimplemented\n");
+}
+
+
+int release_blocks_proc(ext2_filsys fs, blk_t *blocknr, int blockcnt, void *private)
+{
+       printf("%ld ", *blocknr);
+       ext2fs_unmark_block_bitmap(fs,fs->block_map,*blocknr);
+       return 0;
+}
+
+void kill_file_by_inode(ino_t inode)
+{
+       struct ext2_inode inode_buf;
+
+       ext2fs_read_inode(fs, inode, &inode_buf);
+       inode_buf.i_dtime = time(NULL);
+       ext2fs_write_inode(fs, inode, &inode_buf);
+
+       printf("Kill file by inode %ld\n", inode);
+       ext2fs_block_iterate(fs,inode,0,NULL,release_blocks_proc,NULL);
+       ext2fs_unmark_inode_bitmap(fs,fs->inode_map,inode);
+
+       ext2fs_mark_bb_dirty(fs);
+       ext2fs_mark_ib_dirty(fs);
+}
+
+
+void do_kill_file(int argc, char *argv[])
+{
+       ino_t inode_num;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: kill_file <file>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       inode_num = string_to_inode(argv[1]);
+       if (!inode_num) {
+               com_err(argv[0], 0, "Cannot find file");
+               return;
+       }
+       kill_file_by_inode(inode_num);
+}
+
+void do_rm(int argc, char *argv[])
+{
+       int retval;
+       ino_t inode_num;
+       struct ext2_inode inode;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: rm <filename>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       retval = ext2fs_namei(fs, root, cwd, argv[1], &inode_num);
+       if (retval) {
+               com_err(argv[0], 0, "Cannot find file");
+               return;
+       }
+
+       retval = ext2fs_read_inode(fs,inode_num,&inode);
+       if (retval) {
+               com_err(argv[0], retval, "while reading file's inode");
+               return;
+       }
+
+       if (S_ISDIR(inode.i_mode)) {
+               com_err(argv[0], 0, "file is a directory");
+               return;
+       }
+
+       --inode.i_links_count;
+       retval = ext2fs_write_inode(fs,inode_num,&inode);
+       if (retval) {
+               com_err(argv[0], retval, "while writing inode");
+               return;
+       }
+
+       unlink_file_by_name(argv[1]);
+       if (inode.i_links_count == 0)
+               kill_file_by_inode(inode_num);
+}
+
+void do_show_debugfs_params(int argc, char *argv[])
+{
+       FILE *out = stdout;
+
+       fprintf(out, "Open mode: read-%s\n",
+               fs->flags & EXT2_FLAG_RW ? "write" : "only");
+       fprintf(out, "Filesystem in use: %s\n",
+               fs ? fs->device_name : "--none--");
+}
+
+void do_expand_dir(int argc, char *argv[])
+{
+       ino_t inode;
+       int retval;
+
+       if (argc != 2) {
+               com_err(argv[0], 0, "Usage: expand_dir <file>");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+       inode = string_to_inode(argv[1]);
+       if (!inode)
+               return;
+
+       retval = ext2fs_expand_dir(fs, inode);
+       if (retval)
+               com_err("ext2fs_expand_dir", retval, "");
+       return;
+}
+
+void main(int argc, char **argv)
+{
+       int     retval;
+       int     sci_idx;
+       char    *usage = "Usage: debugfs [[-w] device]";
+       char    c;
+       int open_flags = 0;
+       
+       initialize_ext2_error_table();
+
+       while ((c = getopt (argc, argv, "w")) != EOF) {
+               switch (c) {
+               case 'w':
+                       open_flags = EXT2_FLAG_RW;
+                       break;
+               default:
+                       com_err(argv[0], 0, usage);
+                       return;
+               }
+       }
+       if (optind < argc)
+               open_filesystem(argv[optind], open_flags);
+       
+       sci_idx = ss_create_invocation("debugfs", "0.0", (char *) NULL,
+                                      &debug_cmds, &retval);
+       if (retval) {
+               ss_perror(sci_idx, retval, "creating invocation");
+               exit(1);
+       }
+
+       (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval);
+       if (retval) {
+               ss_perror(sci_idx, retval, "adding standard requests");
+               exit (1);
+       }
+
+       ss_listen(sci_idx);
+
+       if (fs)
+               close_filesystem();
+       
+       exit(0);
+}
+
diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
new file mode 100644 (file)
index 0000000..f7f5f08
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * debugfs.h --- header file for the debugfs program
+ */
+
+#include <linux/ext2_fs.h>
+#include "ext2fs/ext2fs.h"
+
+extern ext2_filsys fs;
+extern ino_t   root, cwd;
+
+extern FILE *open_pager(void);
+extern void close_pager(FILE *stream);
+extern int check_fs_open(char *name);
+extern int check_fs_not_open(char *name);
+extern ino_t string_to_inode(char *str);
+
+
+
diff --git a/debugfs/icheck.c b/debugfs/icheck.c
new file mode 100644 (file)
index 0000000..848c76a
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * icheck.c --- given a list of blocks, generate a list of inodes
+ * 
+ * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "debugfs.h"
+
+struct block_info {
+       blk_t   blk;
+       ino_t   ino;
+};
+
+struct block_walk_struct {
+       struct block_info       *barray;
+       int                     blocks_left;
+       int                     num_blocks;
+       ino_t                   inode;
+};
+
+int icheck_proc(ext2_filsys fs,
+               blk_t   *block_nr,
+               int blockcnt,
+               void *private)
+{
+       struct block_walk_struct *bw = (struct block_walk_struct *) private;
+       int     i;
+
+       for (i=0; i < bw->num_blocks; i++) {
+               if (bw->barray[i].blk == *block_nr) {
+                       bw->barray[i].ino = bw->inode;
+                       bw->blocks_left--;
+               }
+       }
+       if (!bw->blocks_left)
+               return BLOCK_ABORT;
+       
+       return 0;
+}
+
+void do_icheck(int argc, char **argv)
+{
+       struct block_walk_struct bw;
+       struct block_info       *binfo;
+       int                     i;
+       ext2_inode_scan         scan = 0;
+       ino_t                   ino;
+       struct ext2_inode       inode;
+       errcode_t               retval;
+       char                    *tmp;
+       char                    *block_buf;
+       
+       if (argc < 2) {
+               com_err(argv[0], 0, "Usage: icheck <block number> ...");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       bw.barray = malloc(sizeof(struct block_info) * argc);
+       if (!bw.barray) {
+               com_err("icheck", ENOMEM,
+                       "while allocating inode info array");
+               return;
+       }
+       memset(bw.barray, 0, sizeof(struct block_info) * argc);
+
+       block_buf = malloc(fs->blocksize * 3);
+       if (!block_buf) {
+               com_err("icheck", ENOMEM, "while allocating block buffer");
+               goto error_out;
+       }
+
+       for (i=1; i < argc; i++) {
+               bw.barray[i-1].blk = strtol(argv[i], &tmp, 0);
+               if (*tmp) {
+                       com_err(argv[0], 0, "Bad block - %s", argv[i]);
+                       return;
+               }
+       }
+
+       bw.num_blocks = bw.blocks_left = argc-1;
+
+       retval = ext2fs_open_inode_scan(fs, 0, &scan);
+       if (retval) {
+               com_err("icheck", retval, "while opening inode scan");
+               goto error_out;
+       }
+
+       retval = ext2fs_get_next_inode(scan, &ino, &inode);
+       if (retval) {
+               com_err("icheck", retval, "while starting inode scan");
+               goto error_out;
+       }
+       
+       while (ino) {
+               if (!inode.i_links_count)
+                       goto next;
+               /*
+                * To handle filesystems touched by 0.3c extfs; can be
+                * removed later.
+                */
+               if (inode.i_dtime)
+                       goto next;
+
+               bw.inode = ino;
+               
+               retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
+                                             icheck_proc, &bw);
+               if (retval) {
+                       com_err("icheck", retval,
+                               "while calling ext2_block_iterate");
+                       goto next;
+               }
+
+               if (bw.blocks_left == 0)
+                       break;
+
+       next:
+               retval = ext2fs_get_next_inode(scan, &ino, &inode);
+               if (retval) {
+                       com_err("icheck", retval,
+                               "while doing inode scan");
+                       goto error_out;
+               }
+       }
+
+       printf("Block\tInode number\n");
+       for (i=0, binfo = bw.barray; i < bw.num_blocks; i++, binfo++) {
+               if (binfo->ino == 0) {
+                       printf("%ld\t<block not found>\n", binfo->blk);
+                       continue;
+               }
+               printf("%ld\t%ld\n", binfo->blk, binfo->ino);
+       }
+
+error_out:
+       free(bw.barray);
+       free(block_buf);
+       if (scan)
+               ext2fs_close_inode_scan(scan);
+       return;
+}
+
+
+
diff --git a/debugfs/ncheck.c b/debugfs/ncheck.c
new file mode 100644 (file)
index 0000000..062e7c5
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * ncheck.c --- given a list of inodes, generate a list of names
+ * 
+ * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "debugfs.h"
+
+struct inode_info {
+       ino_t   ino;
+       ino_t   parent;
+       char    *pathname;
+};
+
+struct inode_walk_struct {
+       struct inode_info       *iarray;
+       int                     inodes_left;
+       int                     num_inodes;
+       int                     position;
+       ino_t                   parent;
+};
+
+int ncheck_proc(struct ext2_dir_entry *dirent,
+               int     offset,
+               int     blocksize,
+               char    *buf,
+               void    *private)
+{
+       struct inode_walk_struct *iw = (struct inode_walk_struct *) private;
+       int     i;
+
+       iw->position++;
+       if (iw->position <= 2)
+               return 0;
+       for (i=0; i < iw->num_inodes; i++) {
+               if (iw->iarray[i].ino == dirent->inode) {
+                       iw->iarray[i].parent = iw->parent;
+                       iw->inodes_left--;
+               }
+       }
+       if (!iw->inodes_left)
+               return DIRENT_ABORT;
+       
+       return 0;
+}
+
+void do_ncheck(int argc, char **argv)
+{
+       struct inode_walk_struct iw;
+       struct inode_info       *iinfo;
+       int                     i;
+       ext2_inode_scan         scan = 0;
+       ino_t                   ino;
+       struct ext2_inode       inode;
+       errcode_t               retval;
+       char                    *tmp;
+       
+       if (argc < 2) {
+               com_err(argv[0], 0, "Usage: ncheck <inode number> ...");
+               return;
+       }
+       if (check_fs_open(argv[0]))
+               return;
+
+       iw.iarray = malloc(sizeof(struct inode_info) * argc);
+       if (!iw.iarray) {
+               com_err("do_ncheck", ENOMEM,
+                       "while allocating inode info array");
+               return;
+       }
+       memset(iw.iarray, 0, sizeof(struct inode_info) * argc);
+
+       for (i=1; i < argc; i++) {
+               iw.iarray[i-1].ino = strtol(argv[i], &tmp, 0);
+               if (*tmp) {
+                       com_err(argv[0], 0, "Bad inode - %s", argv[i]);
+                       return;
+               }
+       }
+
+       iw.num_inodes = iw.inodes_left = argc-1;
+
+       retval = ext2fs_open_inode_scan(fs, 0, &scan);
+       if (retval) {
+               com_err("ncheck", retval, "while opening inode scan");
+               goto error_out;
+       }
+
+       retval = ext2fs_get_next_inode(scan, &ino, &inode);
+       if (retval) {
+               com_err("ncheck", retval, "while starting inode scan");
+               goto error_out;
+       }
+       
+       while (ino) {
+               if (!inode.i_links_count)
+                       goto next;
+               /*
+                * To handle filesystems touched by 0.3c extfs; can be
+                * removed later.
+                */
+               if (inode.i_dtime)
+                       goto next;
+               /* Ignore anything that isn't a directory */
+               if (!S_ISDIR(inode.i_mode))
+                       goto next;
+
+               iw.position = 0;
+               iw.parent = ino;
+               
+               retval = ext2fs_dir_iterate(fs, ino, 0, 0,
+                                           ncheck_proc, &iw);
+               if (retval) {
+                       com_err("ncheck", retval,
+                               "while calling ext2_dir_iterate");
+                       goto next;
+               }
+
+               if (iw.inodes_left == 0)
+                       break;
+
+       next:
+               retval = ext2fs_get_next_inode(scan, &ino, &inode);
+               if (retval) {
+                       com_err("ncheck", retval,
+                               "while doing inode scan");
+                       goto error_out;
+               }
+       }
+
+       for (i=0, iinfo = iw.iarray; i < iw.num_inodes; i++, iinfo++) {
+               if (iinfo->parent == 0)
+                       continue;
+               retval = ext2fs_get_pathname(fs, iinfo->parent,
+                                            iinfo->ino, &iinfo->pathname);
+               if (retval)
+                       com_err("ncheck", retval,
+                               "while resolving pathname for inode %d (%d)",
+                               iinfo->parent, iinfo->ino);
+       }
+       
+       printf("Inode\tPathname\n");
+       for (i=0, iinfo = iw.iarray; i < iw.num_inodes; i++, iinfo++) {
+               if (iinfo->parent == 0) {
+                       printf("%ld\t<inode not found>\n", iinfo->ino);
+                       continue;
+               }
+               printf("%ld\t%s\n", iinfo->ino, iinfo->pathname ?
+                      iinfo->pathname : "<unknown pathname>");
+               if (iinfo->pathname)
+                       free(iinfo->pathname);
+       }
+
+error_out:
+       free(iw.iarray);
+       if (scan)
+               ext2fs_close_inode_scan(scan);
+       return;
+}
+
+
+
diff --git a/debugfs/util.c b/debugfs/util.c
new file mode 100644 (file)
index 0000000..24957fb
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * util.c --- utilities for the debugfs program
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "debugfs.h"
+
+FILE *open_pager(void)
+{
+       FILE *outfile;
+       char *pager = getenv("PAGER");
+
+       if (!pager)
+               outfile = stdout;
+       else {
+               outfile = popen(pager, "w");
+               if (!outfile) outfile = stdout;
+       }
+       return (outfile);
+}
+
+void close_pager(FILE *stream)
+{
+       if (stream && stream != stdout) fclose(stream);
+}
+
+/*
+ * This routine is used whenever a command needs to turn a string into
+ * an inode.
+ */
+ino_t string_to_inode(char *str)
+{
+       ino_t   ino;
+       int     len = strlen(str);
+       int     i;
+       int     retval;
+
+       /*
+        * If the string is of the form <ino>, then treat it as an
+        * inode number.
+        */
+       if ((len > 2) && (str[0] == '<') && (str[len-1] == '>')) {
+               for (i = 1; i < len-1; i++)
+                       if (!isdigit(str[i]))
+                               break;
+               if (i == len-1)
+                       return(atoi(str+1));
+       }
+
+       retval = ext2fs_namei(fs, root, cwd, str, &ino);
+       if (retval) {
+               com_err(str, retval, "");
+               return 0;
+       }
+       return ino;
+}
+
+/*
+ * This routine returns 1 if the filesystem is not open, and prints an
+ * error message to that effect.
+ */
+int check_fs_open(char *name)
+{
+       if (!fs) {
+               com_err(name, 0, "Filesystem not open");
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * This routine returns 1 if a filesystem is open, and prints an
+ * error message to that effect.
+ */
+int check_fs_not_open(char *name)
+{
+       if (fs) {
+               com_err(name, 0,
+                       "Filesystem %s is still open.  Close it first.\n",
+                       fs->device_name);
+               return 1;
+       }
+       return 0;
+}
+
diff --git a/e2fsck/.depend b/e2fsck/.depend
new file mode 100644 (file)
index 0000000..e48c1af
--- /dev/null
@@ -0,0 +1,229 @@
+badblocks.o : badblocks.c /usr/include/time.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h e2fsck.h \
+  /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/sys/time.h /usr/include/linux/time.h \
+  /usr/include/linux/fs.h /usr/include/linux/linkage.h /usr/include/linux/limits.h \
+  /usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
+  /usr/include/linux/net.h /usr/include/linux/socket.h /usr/include/linux/sockios.h \
+  /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
+  /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h \
+  /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \
+  /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h \
+  /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h \
+  /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
+  /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h \
+  ../lib/ext2fs/ext2fs.h ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+dirinfo.o : dirinfo.c ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  e2fsck.h /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/sys/stat.h /usr/include/linux/stat.h \
+  /usr/include/sys/time.h /usr/include/linux/time.h /usr/include/time.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+e2fsck.o : e2fsck.c /usr/include/string.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/fcntl.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/linux/fcntl.h /usr/include/ctype.h /usr/include/termios.h \
+  /usr/include/linux/termios.h /usr/include/time.h /usr/include/getopt.h /usr/include/unistd.h \
+  /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/mntent.h /usr/include/stdio.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/sys/ioctl.h /usr/include/linux/ioctl.h \
+  /usr/include/malloc.h ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  e2fsck.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/sys/stat.h /usr/include/linux/stat.h \
+  /usr/include/sys/time.h /usr/include/linux/time.h /usr/include/linux/fs.h /usr/include/linux/linkage.h \
+  /usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/dirent.h \
+  /usr/include/linux/vfs.h /usr/include/linux/net.h /usr/include/linux/socket.h \
+  /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
+  /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h \
+  /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
+  /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h \
+  /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h \
+  /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
+  /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h \
+  /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h \
+  ../lib/ext2fs/bitops.h ../version.h 
+ehandler.o : ehandler.c /usr/include/stdlib.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/string.h /usr/include/ctype.h /usr/include/termios.h /usr/include/linux/termios.h \
+  /usr/include/sys/resource.h /usr/include/sys/time.h /usr/include/linux/time.h \
+  /usr/include/time.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/limits.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/syslimits.h \
+  /usr/include/limits.h /usr/include/posix1_lim.h /usr/include/linux/limits.h \
+  /usr/include/linux/resource.h e2fsck.h /usr/include/stdio.h /usr/include/libio.h \
+  /usr/include/_G_config.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/wait.h /usr/include/linux/dirent.h \
+  /usr/include/linux/vfs.h /usr/include/linux/net.h /usr/include/linux/socket.h \
+  /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
+  /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h \
+  /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
+  /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h \
+  /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h \
+  /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
+  /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h \
+  /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+flushb.o : flushb.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/sys/ioctl.h /usr/include/linux/ioctl.h /usr/include/termios.h /usr/include/linux/termios.h \
+  /usr/include/linux/fs.h /usr/include/linux/linkage.h /usr/include/linux/limits.h \
+  /usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
+  /usr/include/linux/net.h /usr/include/linux/socket.h /usr/include/linux/sockios.h \
+  /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
+  /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h \
+  /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \
+  /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h \
+  /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h \
+  /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
+  /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h 
+mtrace.o : mtrace.c ./malloc.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h /usr/include/libio.h \
+  /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/limits.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/syslimits.h /usr/include/limits.h \
+  /usr/include/posix1_lim.h /usr/include/linux/limits.h /usr/include/stdlib.h \
+  /usr/include/errno.h /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h 
+pass1.o : pass1.c /usr/include/time.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h e2fsck.h \
+  /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/sys/time.h /usr/include/linux/time.h \
+  /usr/include/linux/fs.h /usr/include/linux/linkage.h /usr/include/linux/limits.h \
+  /usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
+  /usr/include/linux/net.h /usr/include/linux/socket.h /usr/include/linux/sockios.h \
+  /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
+  /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h \
+  /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \
+  /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h \
+  /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h \
+  /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
+  /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h \
+  ../lib/ext2fs/ext2fs.h ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+pass1b.o : pass1b.c /usr/include/time.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h e2fsck.h \
+  /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/sys/time.h /usr/include/linux/time.h \
+  /usr/include/linux/fs.h /usr/include/linux/linkage.h /usr/include/linux/limits.h \
+  /usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
+  /usr/include/linux/net.h /usr/include/linux/socket.h /usr/include/linux/sockios.h \
+  /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
+  /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h \
+  /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \
+  /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h \
+  /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h \
+  /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
+  /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h \
+  ../lib/ext2fs/ext2fs.h ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+pass2.o : pass2.c ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  e2fsck.h /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/sys/stat.h /usr/include/linux/stat.h \
+  /usr/include/sys/time.h /usr/include/linux/time.h /usr/include/time.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+pass3.o : pass3.c ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  e2fsck.h /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/sys/stat.h /usr/include/linux/stat.h \
+  /usr/include/sys/time.h /usr/include/linux/time.h /usr/include/time.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+pass4.o : pass4.c e2fsck.h /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/sys/stat.h /usr/include/linux/stat.h \
+  /usr/include/sys/time.h /usr/include/linux/time.h /usr/include/time.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h \
+  ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../lib/ext2fs/io.h \
+  ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+pass5.o : pass5.c ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  e2fsck.h /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/sys/stat.h /usr/include/linux/stat.h \
+  /usr/include/sys/time.h /usr/include/linux/time.h /usr/include/time.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
+util.o : util.c /usr/include/stdlib.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/string.h /usr/include/ctype.h /usr/include/termios.h /usr/include/linux/termios.h \
+  /usr/include/sys/resource.h /usr/include/sys/time.h /usr/include/linux/time.h \
+  /usr/include/time.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/limits.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/syslimits.h \
+  /usr/include/limits.h /usr/include/posix1_lim.h /usr/include/linux/limits.h \
+  /usr/include/linux/resource.h e2fsck.h /usr/include/stdio.h /usr/include/libio.h \
+  /usr/include/_G_config.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/wait.h /usr/include/linux/dirent.h \
+  /usr/include/linux/vfs.h /usr/include/linux/net.h /usr/include/linux/socket.h \
+  /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
+  /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h \
+  /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
+  /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h \
+  /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h \
+  /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
+  /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h \
+  /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h 
diff --git a/e2fsck/CHANGES b/e2fsck/CHANGES
new file mode 100644 (file)
index 0000000..fa135b6
--- /dev/null
@@ -0,0 +1,53 @@
+[tytso:19940101.1200EST]
+
+Add new options -l and -L, to append to and modify the bad-blocks list.
+
+Fix bugs in bad-block cloning.
+
+[tytso:19931230.1832EST]
+
+Clean up e2fsck and library to be clean even when compiling with full
+warnings enabled.
+
+Make e2fsck deal with zero-length directories correctly.
+
+Deleted inodes from old ext2fs code (inodes with dtime set but
+non-zero link count) are detected, and the user is given the
+opportunity to clear them.
+
+The last bit in the last group of the block bitmap badding was not
+being checked; now fixed.
+
+The free_blocks and free_inodes count in the last group weren't being
+checked.  Now fixed.
+
+[tytso:19931101.0007EST]
+
+Fixed bugs with root reallocation; previously the parent pointers in
+the dirinfo structure would get corrupted, causing many different '..'
+links to be wrong.  Also, the inode link count for the root directory
+wasn't always being set correctly.  (All of this would be fixed on
+the second e2fsck, however).
+
+Fixed to recognize filesystem corruption caused by mke2fs 0.2b (where
+/ and /lost+found had non-zero dtime entries).  Offers to fix /'s
+dtime entry.
+
+e2fsck will now expand the /lost+found directory if it runs out of room.
+
+Fixed dependency on BLOCK_SIZE in pass2.  e2fsck will now handle 4k
+filesystems w/o problems.
+
+e2fsck will now move bad blocks found in the inode bitmaps, block
+bitmaps, and in the inode tables.  (Can't handle bad blocks found in
+the superblock and the group descriptors.)  (Doesn't update alternate
+superblocks, group descriptors.)
+
+e2fsck now supports the -b option, to allow a user to specify an
+alternate superblock.
+
+The -B option now specifies the blocksize of the filesystem.  (If not
+specified, and the -b option is specified, e2fsck will attempt to
+search through various blocksizes to find the correct one.)
+
+Added manual page.
diff --git a/e2fsck/Makefile b/e2fsck/Makefile
new file mode 100644 (file)
index 0000000..c0c64c6
--- /dev/null
@@ -0,0 +1,82 @@
+#
+# Makefile for e2fsck
+#
+
+include ../MCONFIG
+
+MK_CMDS=       ../lib/ss/mk_cmds
+CFLAGS=                $(PROF) $(OPT) $(MTRACE) $(MCHECK) $(WFLAGS) -I../lib
+LDFLAGS=       $(PROF) $(OPT)
+PROGS=         e2fsck flushb
+MANPAGES=      e2fsck.8
+BINDIR=                $(SBINDIR)
+MANDIR=                $(SMANDIR)
+
+LIBS= -L../lib -lss -lcom_err -lext2fs $(CHECKLIB)
+DEPLIBS= ../lib/libss.a ../lib/libcom_err.a ../lib/libext2fs.a
+
+#
+# Flags for using Checker
+#      Note: The optimization flags must include -g
+#
+#MCHECK=       -checker
+#LIBS= -L../lib -lss -lcom_err -lext2fs $(CHECKLIB)
+#DEPLIBS= ../lib/libss.a ../lib/libcom_err.a ../lib/libext2fs.a
+#CHECKLIB= /usr/lib/libchecker.o
+
+#
+# Flags for doing mtrace --- uncomment to produce mtracing e2fsck
+#      Note:  The optimization flags must include -g
+#
+#MTRACE=       -DMTRACE
+#MTRACE_OBJ= mtrace.o
+#OPT= -g
+
+#
+# Flags for doing mcheck --- uncomment to produce mchecking e2fsck
+#      Note:  The optimization flags must include -g
+#
+#MCHECK= -DMCHECK
+
+#
+# Flags for profiling --- uncomment to produce profiling e2fsck
+#
+#PROF=         -pg
+#LIBS= -L../lib -lss -lcom_err_p -lext2fs_p 
+#DEPLIBS= ../lib/libss.a ../lib/libcom_err_p.a ../lib/libext2fs_p.a
+
+OBJS= e2fsck.o pass1.o pass1b.o pass2.o pass3.o pass4.o pass5.o \
+       badblocks.o util.o dirinfo.o ehandler.o $(MTRACE_OBJ)
+
+all: $(PROGS)
+
+#e2fsck: $(OBJS)  $(DEPLIBS)
+#      cc $(LDFLAGS) -o e2fsck $(OBJS) $(LIBS) 
+
+e2fsck: $(OBJS)  $(DEPLIBS)
+       cc $(LDFLAGS) -static -o e2fsck $(OBJS) $(LIBS) 
+
+flushb: flushb.o
+       cc $(LDFLAGS) -o flushb flushb.o $(CHECKLIB)
+
+install:: $(PROGS)
+       for i in $(PROGS); do \
+               $(INSTALLBIN) $$i $(BINDIR)/$$i; \
+       done
+       ln -sf e2fsck $(BINDIR)/fsck.ext2
+
+install:: $(MANPAGES)
+       for i in $(MANPAGES); do \
+               $(INSTALLMAN) $$i $(MANDIR)/$$i; \
+       done
+
+clean:
+       rm -f $(PROGS) \#* *\# *.s *.o *.a *~ core
+
+really-clean:
+       rm -f .depend
+
+dep depend .depend:
+       $(CPP) $(CFLAGS) -M *.c >.depend
+
+include .depend
diff --git a/e2fsck/badblocks.c b/e2fsck/badblocks.c
new file mode 100644 (file)
index 0000000..6dff23d
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * badblocks.c --- replace/append bad blocks to the bad block inode
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ */
+
+#include <time.h>
+
+#include <et/com_err.h>
+#include "e2fsck.h"
+
+static void invalid_block(ext2_filsys fs, blk_t blk)
+{
+       printf("Bad block %lu out of range; ignored.\n", blk);
+       return;
+}
+
+void read_bad_blocks_file(ext2_filsys fs, const char *bad_blocks_file,
+                         int replace_bad_blocks)
+{
+       errcode_t       retval;
+       badblocks_list  bb_list = 0;
+       FILE            *f;
+
+       read_bitmaps(fs);
+       
+       /*
+        * If we're appending to the bad blocks inode, read in the
+        * current bad blocks.
+        */
+       if (!replace_bad_blocks) {
+               retval = ext2fs_read_bb_inode(fs, &bb_list);
+               if (retval) {
+                       com_err("ext2fs_read_bb_inode", retval,
+                               "while reading the bad blocks inode");
+                       fatal_error(0);
+               }
+       }
+       
+       /*
+        * Now read in the bad blocks from the file.
+        */
+       f = fopen(bad_blocks_file, "r");
+       if (!f) {
+               com_err("read_bad_blocks_file", errno,
+                       "while trying to open %s", bad_blocks_file);
+               fatal_error(0);
+       }
+       retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block);
+       fclose (f);
+       if (retval) {
+               com_err("ext2fs_read_bb_FILE", retval,
+                       "while reading in list of bad blocks from file");
+               fatal_error(0);
+       }
+       
+       /*
+        * Finally, update the bad blocks from the bad_block_map
+        */
+       retval = ext2fs_update_bb_inode(fs, bb_list);
+       if (retval) {
+               com_err("ext2fs_update_bb_inode", retval,
+                       "while updating bad block inode");
+               fatal_error(0);
+       }
+
+       badblocks_list_free(bb_list);
+       return;
+}
+
+void test_disk(ext2_filsys fs)
+{
+       errcode_t       retval;
+       badblocks_list  bb_list = 0;
+       FILE            *f;
+       char            buf[1024];
+
+       read_bitmaps(fs);
+       
+       /*
+        * Always read in the current list of bad blocks.
+        */
+       retval = ext2fs_read_bb_inode(fs, &bb_list);
+       if (retval) {
+               com_err("ext2fs_read_bb_inode", retval,
+                       "while reading the bad blocks inode");
+               fatal_error(0);
+       }
+       
+       /*
+        * Now run the bad blocks program
+        */
+       sprintf(buf, "badblocks %s%s %ld", preen ? "" : "-s ",
+               fs->device_name,
+               fs->super->s_blocks_count);
+       if (verbose)
+               printf("Running command: %s\n", buf);
+       f = popen(buf, "r");
+       if (!f) {
+               com_err("popen", errno,
+                       "while trying to run %s", buf);
+               fatal_error(0);
+       }
+       retval = ext2fs_read_bb_FILE(fs, f, &bb_list, invalid_block);
+       fclose (f);
+       if (retval) {
+               com_err("ext2fs_read_bb_FILE", retval,
+                       "while processing list of bad blocks from program");
+               fatal_error(0);
+       }
+       
+       /*
+        * Finally, update the bad blocks from the bad_block_map
+        */
+       retval = ext2fs_update_bb_inode(fs, bb_list);
+       if (retval) {
+               com_err("ext2fs_update_bb_inode", retval,
+                       "while updating bad block inode");
+               fatal_error(0);
+       }
+
+       badblocks_list_free(bb_list);
+       return;
+}
+
diff --git a/e2fsck/dirinfo.c b/e2fsck/dirinfo.c
new file mode 100644 (file)
index 0000000..101ccee
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * dirinfo.c --- maintains the directory information table for e2fsck.
+ *
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <et/com_err.h>
+#include "e2fsck.h"
+
+static int             dir_info_count = 0;
+static int             dir_info_size = 0;
+static struct dir_info *dir_info = 0;
+
+int get_num_dirs(ext2_filsys fs)
+{
+       int     i, num_dirs;
+
+       num_dirs = 0;
+       for (i = 0; i < fs->group_desc_count; i++)
+               num_dirs += fs->group_desc[i].bg_used_dirs_count;
+
+       return num_dirs;
+}
+
+/*
+ * This subroutine is called during pass1 to stash away the block
+ * numbers for the directory, which we will need later.  The idea is
+ * to avoid reading directory inodes twice.
+ */
+void add_dir_info(ext2_filsys fs, ino_t ino, ino_t parent,
+               struct ext2_inode *inode)
+{
+       struct dir_info *dir;
+       int     i, j;
+
+#if 0
+       printf("add_dir_info for inode %d...\n", ino);
+#endif
+       if (!dir_info) {
+               dir_info_count = 0;
+               dir_info_size = get_num_dirs(fs) + 10;
+
+               dir_info  = allocate_memory(dir_info_size *
+                                          sizeof (struct dir_info),
+                                          "directory map");
+       }
+       
+       if (dir_info_count >= dir_info_size) {
+               dir_info_size += 10;
+               dir_info = realloc(dir_info,
+                                 dir_info_size * sizeof(struct dir_info));
+       }
+
+       /*
+        * Normally, add_dir_info is called with each inode in
+        * sequential order; but once in a while (like when pass 3
+        * needs to recreate the root directory or lost+found
+        * directory) it is called out of order.  In those cases, we
+        * need to move the dir_info entries down to make room, since
+        * the dir_info array needs to be sorted by inode number for
+        * get_dir_info()'s sake.
+        */
+       if (dir_info_count && dir_info[dir_info_count-1].ino > ino) {
+               for (i = dir_info_count-1; i > 0; i--)
+                       if (dir_info[i-1].ino < ino)
+                               break;
+               dir = &dir_info[i];
+               if (dir->ino != ino) 
+                       for (j = dir_info_count++; j > i; j--)
+                               dir_info[j] = dir_info[j-1];
+       } else
+               dir = &dir_info[dir_info_count++];
+       
+       dir->ino = ino;
+       dir->dotdot = parent;
+       dir->parent = parent;
+}
+
+/*
+ * get_dir_info() --- given an inode number, try to find the directory
+ * information entry for it.
+ */
+struct dir_info *get_dir_info(ino_t ino)
+{
+       int     low, high, mid;
+
+       low = 0;
+       high = dir_info_count-1;
+       if (ino == dir_info[low].ino)
+               return &dir_info[low];
+       if  (ino == dir_info[high].ino)
+               return &dir_info[high];
+
+       while (low < high) {
+               mid = (low+high)/2;
+               if (mid == low || mid == high)
+                       break;
+               if (ino == dir_info[mid].ino)
+                       return &dir_info[mid];
+               if (ino < dir_info[mid].ino)
+                       high = mid;
+               else
+                       low = mid;
+       }
+       return 0;
+}
+
+/*
+ * Free the dir_info structure when it isn't needed any more.
+ */
+void free_dir_info(ext2_filsys fs)
+{
+       if (dir_info) {
+               free(dir_info);
+               dir_info = 0;
+       }
+       dir_info_size = 0;
+       dir_info_count = 0;
+}
diff --git a/e2fsck/e2fsck.8 b/e2fsck/e2fsck.8
new file mode 100644 (file)
index 0000000..d79903c
--- /dev/null
@@ -0,0 +1,127 @@
+.\" -*- nroff -*-
+.\" Copyright 1993, 1994 by Theodore Ts'o.  All Rights Reserved.
+.\" This file may be copied under the terms of the GNU Public License.
+.\" 
+.TH NEW-E2FSCK 8 "March 1994" "Version 0.5"
+.SH NAME
+e2fsck \- check a Linux second extended file system
+.SH SYNOPSIS
+.B e2fsck
+[
+.B \-panyrdfvtFV
+]
+[
+.B \-b
+.I superblock
+]
+[
+.B \-B
+.I blocksize
+]
+[
+.B \-l|-L
+.I bad_blocks_file
+]
+.I device
+.SH DESCRIPTION
+.B e2fsck
+is used to check a Linux second extended file system.
+.TP
+.I device
+is the special file corresponding to the device (e.g /dev/hdXX).
+.SH OPTIONS
+.TP
+.I -b superblock
+Instead of using the normal superblock, use the alternative superblock
+specified by 
+.IR superblock .
+.TP
+.I -d
+Print debugging output (useless unless you are debugging
+.B e2fsck
+).
+.TP
+.I -f
+Force checking even if the file system seems clean.
+.TP
+.I -F
+Flush the filesystem device's buffer caches before beginning.  Only
+really useful for doing e2fsck time trials.
+.TP
+.I -l filename
+Add the blocks listed in the file specified by 
+.I filename
+to the list of bad blocks.
+.TP
+.I -L filename
+Set the bad blocks list to be the list of blocks specified by 
+.IR filename .
+(This option is the same as the 
+.I -l
+option, except the bad blocks list is cleared before the blocks listed
+in the file are added to the bad blocks list.)
+.TP
+.I -n
+Open the filesystem read-only, and assume an answer of ``no'' to all
+questions.  Allows
+.B e2fsck
+to be used non-interactively.  (Note: if the 
+.I -l
+or
+.I -L
+options are specified in addition to the 
+.I -n
+option, then the filesystem will be opened read-write, to permit the
+bad-blocks list to be updated.  However, no other changes will be made
+to the filesystem.)
+.TP
+.I -p
+Automatically repair ("preen") the file system without any questions.
+The
+.I -a
+option is provided for backwards compatibility.
+.TP
+.I -t
+Print timing statistics for
+.BR e2fsck .
+If this option is used twice, additional timing statistics are printed
+on a pass by pass basis.
+.TP
+.I -v
+Verbose mode.
+.TP
+.I -V
+Print version information and exit.
+.TP
+.I -y
+Assume an answer of ``yes'' to all questions; allows 
+.B e2fsck
+to be used non-interactively.
+.SH EXIT CODE
+The exit code returned by
+.B e2fsck
+is the sum of the following conditions:
+.br
+\      0\      \-\ No errors
+.br
+\      1\      \-\ File system errors corrected
+.br
+\      2\      \-\ File system errors corrected, system should
+.br
+\      \       \ \ be rebooted if file system was mounted
+.br
+\      4\      \-\ File system errors left uncorrected
+.br
+\      8\      \-\ Operational error
+.br
+\      16\     \-\ Usage or syntax error
+.br
+\      128\    \-\ Shared library error
+.br
+.SH AUTHOR
+This version of 
+.B e2fsck
+is written by Theodore Ts'o <tytso@mit.edu>.
+.SH SEE ALSO
+.BR mke2fs (8),
+.BR tune2fs (8)
diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c
new file mode 100644 (file)
index 0000000..37d202b
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * e2fsck.c - a consistency checker for the new extended file system.
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ */
+
+/* Usage: e2fsck [-dfpnsvy] device
+ *     -d -- debugging this program
+ *     -f -- check the fs even if it is marked valid
+ *     -p -- "preen" the filesystem
+ *     -n -- open the filesystem r/o mode; never try to fix problems
+ *     -v -- verbose (tells how many files)
+ *     -y -- always answer yes to questions
+ *
+ * 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 :-). 
+ */
+
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <termios.h>
+#include <time.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <mntent.h>
+#include <sys/ioctl.h>
+#include <malloc.h>
+
+#include "et/com_err.h"
+#include "e2fsck.h"
+#include "../version.h"
+
+extern int isatty(int);
+
+const char * program_name = "e2fsck";
+const char * device_name = NULL;
+
+/* Command line options */
+int nflag = 0;
+int yflag = 0;
+int tflag = 0;                 /* Do timing */
+int cflag = 0;                 /* check disk */
+int preen = 0;
+int rwflag = 1;
+int inode_buffer_blocks = 0;
+blk_t superblock;
+int blocksize = 0;
+int verbose = 0;
+int list = 0;
+int debug = 0;
+int force = 0;
+static int show_version_only = 0;
+
+static int replace_bad_blocks = 0;
+static char *bad_blocks_file = 0;
+
+static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
+
+struct resource_track  global_rtrack;
+
+static int root_filesystem = 0;
+static int read_only_root = 0;
+
+static void usage(NOARGS)
+{
+       fprintf(stderr,
+               "Usage: %s [-panyrdfvtFV] [-b superblock] [-B blocksize]\n"
+               "\t\tdevice\n", program_name);
+       exit(FSCK_USAGE);
+}
+
+static void show_stats(ext2_filsys fs)
+{
+       int inodes, inodes_used, blocks, blocks_used;
+       int dir_links;
+       int num_files, num_links;
+
+       dir_links = 2 * fs_directory_count - 1;
+       num_files = fs_total_count - dir_links;
+       num_links = fs_links_count - dir_links;
+       inodes = fs->super->s_inodes_count;
+       inodes_used = (fs->super->s_inodes_count -
+                      fs->super->s_free_inodes_count);
+       blocks = fs->super->s_blocks_count;
+       blocks_used = (fs->super->s_blocks_count -
+                      fs->super->s_free_blocks_count);
+       
+       if (!verbose) {
+               printf("%s: %d/%d files, %d/%d blocks\n", device_name,
+                      inodes_used, inodes, blocks_used, blocks);
+               return;
+       }
+       printf ("\n%6d inode%s used (%d%%)\n", inodes_used,
+               (inodes_used != 1) ? "s" : "",
+               100 * inodes_used / inodes);
+       printf ("%6d block%s used (%d%%)\n"
+               "%6d bad block%s\n", blocks_used,
+               (blocks_used != 1) ? "s" : "",
+               100 * blocks_used / blocks, fs_badblocks_count,
+               fs_badblocks_count != 1 ? "s" : "");
+       printf ("\n%6d regular file%s\n"
+               "%6d director%s\n"
+               "%6d character device file%s\n"
+               "%6d block device file%s\n"
+               "%6d fifo%s\n"
+               "%6d link%s\n"
+               "%6d symbolic link%s (%d fast symbolic link%s)\n"
+               "%6d socket%s\n"
+               "------\n"
+               "%6d file%s\n",
+               fs_regular_count, (fs_regular_count != 1) ? "s" : "",
+               fs_directory_count, (fs_directory_count != 1) ? "ies" : "y",
+               fs_chardev_count, (fs_chardev_count != 1) ? "s" : "",
+               fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "",
+               fs_fifo_count, (fs_fifo_count != 1) ? "s" : "",
+               fs_links_count - dir_links,
+               ((fs_links_count - dir_links) != 1) ? "s" : "",
+               fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "",
+               fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "",
+               fs_sockets_count, (fs_sockets_count != 1) ? "s" : "",
+               fs_total_count - dir_links,
+               ((fs_total_count - dir_links) != 1) ? "s" : "");
+}
+
+static void check_mount(NOARGS)
+{
+       FILE * f;
+       struct mntent * mnt;
+       int cont;
+       int fd;
+
+       if ((f = setmntent (MOUNTED, "r")) == NULL)
+               return;
+       while ((mnt = getmntent (f)) != NULL)
+               if (strcmp (device_name, mnt->mnt_fsname) == 0)
+                       break;
+       endmntent (f);
+       if (!mnt)
+               return;
+
+       if  (!strcmp(mnt->mnt_dir, "/"))
+               root_filesystem = 1;
+
+       /*
+        * If the root is mounted read-only, then /etc/mtab is
+        * probably not correct; so we won't issue a warning based on
+        * it.
+        */
+       fd = open(MOUNTED, O_RDWR);
+       if (fd < 0) {
+               if (errno == EROFS) {
+                       read_only_root = 1;
+                       return;
+               }
+       } else
+               close(fd);
+       
+       if (!rwflag) {
+               printf("Warning!  %s is mounted.\n", device_name);
+               return;
+       }
+
+       printf ("%s is mounted.  ", device_name);
+       if (isatty (0) && isatty (1))
+               cont = ask_yn("Do you really want to continue", -1);
+       else
+               cont = 0;
+       if (!cont) {
+               printf ("check aborted.\n");
+               exit (0);
+       }
+       return;
+}
+
+static void sync_disks(NOARGS)
+{
+       sync();
+       sync();
+       sleep(1);
+       sync();
+}
+
+static void check_super_block(ext2_filsys fs)
+{
+       blk_t   first_block, last_block;
+       int     blocks_per_group = fs->super->s_blocks_per_group;
+       int     i;
+
+       first_block =  fs->super->s_first_data_block;
+       last_block = first_block + blocks_per_group;
+
+       for (i = 0; i < fs->group_desc_count; i++) {
+               if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
+                   (fs->group_desc[i].bg_block_bitmap >= last_block)) {
+                       printf("Block bitmap %ld for group %d not in group.\n",
+                              fs->group_desc[i].bg_block_bitmap, i);
+                       fatal_error(0);
+               }
+               if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
+                   (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
+                       printf("Inode bitmap %ld for group %d not in group.\n",
+                              fs->group_desc[i].bg_inode_bitmap, i);
+                       fatal_error(0);
+               }
+               if ((fs->group_desc[i].bg_inode_table < first_block) ||
+                   ((fs->group_desc[i].bg_inode_table +
+                     fs->inode_blocks_per_group - 1) >= last_block)) {
+                       printf("Inode table %ld for group %d not in group.\n",
+                              fs->group_desc[i].bg_inode_table, i);
+                       fatal_error(0);
+               }
+               first_block += fs->super->s_blocks_per_group;
+               last_block += fs->super->s_blocks_per_group;
+       }
+       return;
+}
+
+/*
+ * This routine checks to see if a filesystem can be skipped; if so,
+ * it will exit with E2FSCK_OK.  Under some conditions it will print a
+ * message explaining why a check is being forced.
+ */
+static void check_if_skip(ext2_filsys fs)
+{
+       const char *reason = NULL;
+       
+       if (force || bad_blocks_file || cflag)
+               return;
+       
+       if (fs->super->s_state & EXT2_ERROR_FS)
+               reason = "contains a file system with errors";
+       else if (fs->super->s_mnt_count >=
+                (unsigned) fs->super->s_max_mnt_count)
+               reason = "has reached maximal mount count";
+       else if (fs->super->s_checkinterval &&
+                time(0) >= (fs->super->s_lastcheck +
+                            fs->super->s_checkinterval))
+               reason = "has gone too long without being checked";
+       if (reason) {
+               printf("%s %s, check forced.\n", device_name, reason);
+               return;
+       }
+       if (fs->super->s_state & EXT2_VALID_FS) {
+               printf("%s is clean, no check.\n", device_name);
+               exit(FSCK_OK);
+       }
+}      
+
+static void PRS(int argc, char *argv[])
+{
+       int flush = 0;
+       char c;
+#ifdef MTRACE
+       extern void *mallwatch;
+#endif
+       char *oldpath, newpath[PATH_MAX];
+
+       /* Update our PATH to include /sbin  */
+       strcpy(newpath, "PATH=/sbin:");
+       if ((oldpath = getenv("PATH")) != NULL)
+               strcat(newpath, oldpath);
+       putenv(newpath);
+
+       setbuf(stdout, NULL);
+       setbuf(stderr, NULL);
+       initialize_ext2_error_table();
+       
+       if (argc && *argv)
+               program_name = *argv;
+       while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:")) != EOF)
+               switch (c) {
+               case 'p':
+               case 'a':
+                       preen = 1;
+                       yflag = nflag = 0;
+                       break;
+               case 'n':
+                       nflag = 1;
+                       preen = yflag = 0;
+                       break;
+               case 'y':
+                       yflag = 1;
+                       preen = nflag = 0;
+                       break;
+               case 't':
+                       tflag++;
+                       break;
+               case 'c':
+                       cflag++;
+                       break;
+               case 'r':
+                       /* What we do by default, anyway! */
+                       break;
+               case 'b':
+                       superblock = atoi(optarg);
+                       break;
+               case 'B':
+                       blocksize = atoi(optarg);
+                       break;
+               case 'I':
+                       inode_buffer_blocks = atoi(optarg);
+                       break;
+               case 'P':
+                       process_inode_size = atoi(optarg);
+                       break;
+               case 'L':
+                       replace_bad_blocks++;
+               case 'l':
+                       bad_blocks_file = malloc(strlen(optarg)+1);
+                       if (!bad_blocks_file)
+                               fatal_error("Couldn't malloc bad_blocks_file");
+                       strcpy(bad_blocks_file, optarg);
+                       break;
+               case 'd':
+                       debug = 1;
+                       break;
+               case 'f':
+                       force = 1;
+                       break;
+               case 'F':
+                       flush = 1;
+                       break;
+               case 'v':
+                       verbose = 1;
+                       break;
+               case 'V':
+                       show_version_only = 1;
+                       break;
+#ifdef MTRACE
+               case 'M':
+                       mallwatch = (void *) strtol(optarg, NULL, 0);
+                       break;
+#endif
+               default:
+                       usage ();
+               }
+       if (show_version_only)
+               return;
+       if (optind != argc - 1)
+               usage ();
+       if (nflag && !bad_blocks_file && !cflag)
+               rwflag = 0;
+       device_name = argv[optind];
+       if (flush) {
+               int     fd = open(device_name, O_RDONLY, 0);
+
+               if (fd < 0) {
+                       com_err("open", errno, "while opening %s for flushing",
+                               device_name);
+                       exit(FSCK_ERROR);
+               }
+               if (ioctl(fd, BLKFLSBUF, 0) < 0) {
+                       com_err("BLKFLSBUF", errno, "while trying to flush %s",
+                               device_name);
+                       exit(FSCK_ERROR);
+               }
+               close(fd);
+       }
+}
+                                       
+int main (int argc, char *argv[])
+{
+       errcode_t       retval = 0;
+       int             exit_value = FSCK_OK;
+       int             i;
+       ext2_filsys     fs;
+       
+#ifdef MTRACE
+       mtrace();
+#endif
+#ifdef MCHECK
+       mcheck(0);
+#endif
+       
+       init_resource_track(&global_rtrack);
+
+       PRS(argc, argv);
+
+       if (!preen)
+               fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
+                        E2FSPROGS_VERSION, E2FSPROGS_DATE,
+                        EXT2FS_VERSION, EXT2FS_DATE);
+
+       if (show_version_only)
+               exit(0);
+       
+       check_mount();
+       
+       if (!preen && !nflag && !yflag) {
+               if (!isatty (0) || !isatty (1))
+                       die ("need terminal for interactive repairs");
+       }
+       sync_disks();
+       if (superblock && blocksize) {
+               retval = ext2fs_open(device_name, rwflag ? EXT2_FLAG_RW : 0,
+                                    superblock, blocksize, unix_io_manager,
+                                    &fs);
+       } else if (superblock) {
+               for (i=0; possible_block_sizes[i]; i++) {
+                       retval = ext2fs_open(device_name,
+                                            rwflag ? EXT2_FLAG_RW : 0,
+                                            superblock,
+                                            possible_block_sizes[i],
+                                            unix_io_manager, &fs);
+                       if (!retval)
+                               break;
+               }
+       } else 
+               retval = ext2fs_open(device_name, rwflag ? EXT2_FLAG_RW : 0,
+                                    0, 0, unix_io_manager, &fs);
+       if (retval) {
+               com_err(program_name, retval, "while trying to open %s",
+                       device_name);
+               printf("Couldn't find valid filesystem superblock.\n");
+               fatal_error(0);
+       }
+       /*
+        * If the user specified a specific superblock, presumably the
+        * master superblock has been trashed.  So we mark the
+        * superblock as dirty, so it can be written out.
+        */
+       if (superblock && rwflag)
+               ext2fs_mark_super_dirty(fs);
+
+       ehandler_init(fs->io);
+
+       check_super_block(fs);
+       check_if_skip(fs);
+       if (bad_blocks_file)
+               read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
+       else if (cflag)
+               test_disk(fs);
+
+       /*
+        * Mark the system as valid, 'til proven otherwise
+        */
+       ext2fs_mark_valid(fs);
+       
+       pass1(fs);
+       pass2(fs);
+       pass3(fs);
+       pass4(fs);
+       pass5(fs);
+
+#ifdef MTRACE
+       mtrace_print("Cleanup");
+#endif
+       if (ext2fs_test_changed(fs)) {
+               exit_value = FSCK_NONDESTRUCT;
+               if (!preen)
+                       printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
+                              device_name);
+               if (root_filesystem && !read_only_root) {
+                       printf("%s: ***** REBOOT LINUX *****\n", device_name);
+                       exit_value = FSCK_REBOOT;
+               }
+       }
+       if (!ext2fs_test_valid(fs))
+               exit_value = FSCK_UNCORRECTED;
+       if (rwflag) {
+               if (ext2fs_test_valid(fs))
+                       fs->super->s_state = EXT2_VALID_FS;
+               else
+                       fs->super->s_state &= ~EXT2_VALID_FS;
+               fs->super->s_mnt_count = 0;
+               fs->super->s_lastcheck = time(NULL);
+               ext2fs_mark_super_dirty(fs);
+       }
+       show_stats(fs);
+
+       write_bitmaps(fs);
+       ext2fs_close(fs);
+       sync_disks();
+       
+       if (tflag)
+               print_resource_track(&global_rtrack);
+       
+       return exit_value;
+}
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
new file mode 100644 (file)
index 0000000..a25f461
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * e2fsck.h
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ * 
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs/ext2fs.h"
+
+#ifdef __STDC__
+#define NOARGS void
+#else
+#define NOARGS
+#define const
+#endif
+
+/*
+ * Exit codes used by fsck-type programs
+ */
+#define FSCK_OK          0     /* No errors */
+#define FSCK_NONDESTRUCT 1     /* File system errors corrected */
+#define FSCK_REBOOT      2     /* System should be rebooted */
+#define FSCK_UNCORRECTED 4     /* File system errors left uncorrected */
+#define FSCK_ERROR       8     /* Operational error */
+#define FSCK_USAGE       16    /* Usage or syntax error */
+#define FSCK_LIBRARY     128   /* Shared library error */
+
+/*
+ * Inode count arrays
+ */
+extern unsigned short * inode_count;
+extern unsigned short * inode_link_info;
+
+/*
+ * The directory information structure; stores directory information
+ * collected in earlier passes, to avoid disk i/o in fetching the
+ * directoryt information.
+ */
+struct dir_info {
+       ino_t                   ino;    /* Inode number */
+       ino_t                   dotdot; /* Parent according to '..' */
+       ino_t                   parent; /* Parent according to treewalk */
+};
+
+struct dir_block_struct {
+       ino_t   ino;
+       blk_t   blk;
+       int     blockcnt;
+};
+
+struct dir_block_struct *dir_blocks;
+int    dir_block_count;
+int    dir_block_size;
+
+/*
+ * This structure is used for keeping track of how much resources have
+ * been used for a particular pass of e2fsck.
+ */
+struct resource_track {
+       struct timeval time_start;
+       struct timeval user_start;
+       struct timeval system_start;
+       void    *brk_start;
+};
+
+/*
+ * Variables
+ */
+extern const char * program_name;
+extern const char * device_name;
+
+extern char * inode_used_map;  /* Inodes which are in use */
+extern char * inode_bad_map;   /* Inodes which are bad in some way */
+extern char * inode_dir_map;   /* Inodes which are directories */
+
+extern char * block_found_map; /* Blocks which are used by an inode */
+extern char * block_dup_map;   /* Blocks which are used by more than once */
+
+extern const char *fix_msg[2]; /* Fixed or ignored! */
+extern const char *clear_msg[2]; /* Cleared or ignored! */
+
+/* Command line options */
+extern int nflag;
+extern int yflag;
+extern int tflag;
+extern int preen;
+extern int verbose;
+extern int list;
+extern int debug;
+extern int force;
+
+extern int rwflag;
+
+extern int inode_buffer_blocks;
+extern int process_inode_size;
+extern int directory_blocks;
+
+extern int no_bad_inode;
+extern int no_lpf;
+extern int lpf_corrupted;
+
+/* Files counts */
+extern int fs_directory_count;
+extern int fs_regular_count;
+extern int fs_blockdev_count;
+extern int fs_chardev_count;
+extern int fs_links_count;
+extern int fs_symlinks_count;
+extern int fs_fast_symlinks_count;
+extern int fs_fifo_count;
+extern int fs_total_count;
+extern int fs_badblocks_count;
+extern int fs_sockets_count;
+
+extern struct resource_track   global_rtrack;
+
+/*
+ * Procedure declarations
+ */
+
+extern void pass1(ext2_filsys fs);
+extern void pass1_dupblocks(ext2_filsys fs, char *block_buf);
+extern void pass2(ext2_filsys fs);
+extern void pass3(ext2_filsys fs);
+extern void pass4(ext2_filsys fs);
+extern void pass5(ext2_filsys fs);
+
+/* badblock.c */
+extern void read_bad_blocks_file(ext2_filsys fs, const char *bad_blocks_file,
+                                int replace_bad_blocks);
+extern void test_disk(ext2_filsys fs);
+
+/* dirinfo.c */
+extern void add_dir_info(ext2_filsys fs, ino_t ino, ino_t parent,
+                      struct ext2_inode *inode);
+extern struct dir_info *get_dir_info(ino_t ino);
+extern void free_dir_info(ext2_filsys fs);
+extern int get_num_dirs(ext2_filsys fs);
+
+/* ehandler.c */
+extern const char *ehandler_operation(const char *op);
+extern void ehandler_init(io_channel channel);
+
+/* util.c */
+extern void *allocate_memory(int size, const char *description);
+extern int ask(const char * string, int def);
+extern int ask_yn(const char * string, int def);
+extern void fatal_error (const char * fmt_string);
+extern void read_bitmaps(ext2_filsys fs);
+extern void write_bitmaps(ext2_filsys fs);
+extern void preenhalt(NOARGS);
+extern void print_resource_track(struct resource_track *track);
+extern void init_resource_track(struct resource_track *track);
+extern int inode_has_valid_blocks(struct ext2_inode *inode);
+#ifdef MTRACE
+extern void mtrace_print(char *mesg);
+#endif
+
+#define die(str)       fatal_error(str)
+
+/*
+ * pass3.c
+ */
+extern int reconnect_file(ext2_filsys fs, ino_t inode);
diff --git a/e2fsck/ehandler.c b/e2fsck/ehandler.c
new file mode 100644 (file)
index 0000000..96aedfb
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * ehandler.c --- handle bad block errors which come up during the
+ *     course of an e2fsck session.
+ * 
+ * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <termios.h>
+#include <sys/resource.h>
+
+#include "e2fsck.h"
+
+static const char *operation;
+
+static errcode_t e2fsck_handle_read_error(io_channel channel,
+                                         unsigned long block,
+                                         int count,
+                                         void *data,
+                                         size_t size,
+                                         int actual,
+                                         errcode_t error)
+{
+       int     i;
+       char    *p;
+
+       /*
+        * If more than one block was read, try reading each block
+        * separately.  We could use the actual bytes read to figure
+        * out where to start, but we don't bother.
+        */
+       if (count > 1) {
+               p = (char *) data;
+               for (i=0; i < count; i++, p += channel->block_size, block++) {
+                       error = io_channel_read_blk(channel, block,
+                                                   1, p);
+                       if (error)
+                               return error;
+               }
+               return 0;
+       }
+       if (operation)
+               printf("Error reading block %ld (%s) while %s.  ", block,
+                      error_message(error), operation);
+       else
+               printf("Error reading block %ld (%s).  ", block,
+                      error_message(error));
+       preenhalt();
+       if (ask("Ignore error", 1))
+               return 0;
+
+       return error;
+}
+
+static errcode_t e2fsck_handle_write_error(io_channel channel,
+                                           unsigned long block,
+                                           int count,
+                                           const void *data,
+                                           size_t size,
+                                           int actual,
+                                           errcode_t error)
+{
+       int             i;
+       const char      *p;
+       
+       /*
+        * If more than one block was written, try writing each block
+        * separately.  We could use the actual bytes read to figure
+        * out where to start, but we don't bother.
+        */
+       if (count > 1) {
+               p = (const char *) data;
+               for (i=0; i < count; i++, p += channel->block_size, block++) {
+                       error = io_channel_write_blk(channel, block,
+                                                    1, p);
+                       if (error)
+                               return error;
+               }
+               return 0;
+       }
+       
+       if (operation)
+               printf("Error writing block %ld (%s) while %s.  ", block,
+                      error_message(error), operation);
+       else
+               printf("Error writing block %ld (%s).  ", block,
+                      error_message(error));
+       preenhalt();
+       if (ask("Ignore error", 1))
+               return 0;
+
+       return error;
+}
+
+const char *ehandler_operation(const char *op)
+{
+       const char *ret = operation;
+
+       operation = op;
+       return ret;
+}
+
+void ehandler_init(io_channel channel)
+{
+       channel->read_error = e2fsck_handle_read_error;
+       channel->write_error = e2fsck_handle_write_error;
+}
diff --git a/e2fsck/flushb.c b/e2fsck/flushb.c
new file mode 100644 (file)
index 0000000..eba4e85
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * flushb.c --- This routine flushes the disk buffers for a disk
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <linux/fs.h>
+
+#ifdef __STDC__
+#define NOARGS void
+#else
+#define NOARGS
+#define const
+#endif
+
+const char *progname;
+
+static void usage(NOARGS)
+{
+       fprintf(stderr, "Usage: %s disk\n", progname);
+       exit(1);
+}      
+       
+int main(int argc, char **argv)
+{
+       int     fd;
+       
+       progname = argv[0];
+       if (argc != 2)
+               usage();
+
+       fd = open(argv[1], O_RDONLY, 0);
+       if (fd < 0) {
+               perror("open");
+               exit(1);
+       }
+       /*
+        * Note: to reread the partition table, use the ioctl
+        * BLKRRPART instead of BLKFSLBUF.
+        */
+       if (ioctl(fd, BLKFLSBUF, 0) < 0) {
+               perror("ioctl");
+               exit(1);
+       }
+       return 0;
+}
diff --git a/e2fsck/images/README b/e2fsck/images/README
new file mode 100644 (file)
index 0000000..bd111fd
--- /dev/null
@@ -0,0 +1,59 @@
+These images contain various forms of corrupted filesystem which
+e2fsck will correct.  They are used as a regression test for e2fsck.
+
+The test_script program will automatically run e2fsck against the
+filesystem images.  It will run them two times, and display the exit
+status for each run.  The meaning of the exit status codes are as
+follows:
+
+       0               No filesystem errors were detected
+       1               Filesystem errors detected, but corrected
+       2               System should be rebooted
+       4               Filesystem errors left uncorrected
+       8               Operational error (generally means internal error,
+                               or filesystem error that the e2fsck was not
+                               prepared to deal with)
+       16              Usage or syntax error
+
+During the regression test, the first exit code should be 1 (with the
+exception of the empty filesystem, empty.img, which will have an exit
+code of 0), and the second exit code should be 0.  In other words, all
+of the test filesystems in this directory (with the exception of
+empty.img) have some sort of filesystem corruption, which e2fsck
+should fix on the first pass.  After the first pass, e2fsck should
+leave a fully consistent filesystem with no detectable errors found in
+the second pass.
+
+NOTE: It appears that at least some versions of the original e2fsck do
+not exit with an exit status code of 1 after correcting filesystem
+errors.  So if you modify the test_script to try running these
+filesystems against the original e2fsck, you will have to inspect the
+test_script.log file manually.
+
+--------------------------------------------------------------
+Here's a one-line descriptons of the various test images in this
+directory:
+
+baddir.img             Filesystem with a corrupted directory
+badinode.img           Filesystem with various different corrupted inode
+                               entries.
+badlkcnt.img           Filesystem with deleted files with non-zero link count
+badroot.img            Filesystem with a file for a root directory
+badtable.img           Filesystem with blocks shared between the bitmaps and
+                               inode table blocks and the bad block inode
+bbfile.img             Filesystem with files containing bad blocks
+bitmaps.img            Filesystem with corrupted inode and block bitmaps
+dirlink.img            Filesystem with a hard link to a directory
+dup.img                        Filesystem with blocks claimed by two different files
+dup2.img               Filesystem with blocks claimed by three different files
+end-bitmap.img         Filesystem with corruption at the end of the block 
+                               bitmap
+expand.img             Tests e2fsck's ability to expand lost+found if 
+                               necessary
+lpf.img                        Filesystem with disconnected files and no /lost+found 
+                               directory
+mke2fs2b.img           Filesystem with corruption similar to that
+                               created by mke2fs version 0.2b
+noroot.img             Filesystem with a deleted root directory.
+
+
diff --git a/e2fsck/images/baddir.img.gz b/e2fsck/images/baddir.img.gz
new file mode 100644 (file)
index 0000000..c7af6c5
Binary files /dev/null and b/e2fsck/images/baddir.img.gz differ
diff --git a/e2fsck/images/badinode.img.gz b/e2fsck/images/badinode.img.gz
new file mode 100644 (file)
index 0000000..7d10bc1
Binary files /dev/null and b/e2fsck/images/badinode.img.gz differ
diff --git a/e2fsck/images/badlkcnt.img.gz b/e2fsck/images/badlkcnt.img.gz
new file mode 100644 (file)
index 0000000..96509f5
Binary files /dev/null and b/e2fsck/images/badlkcnt.img.gz differ
diff --git a/e2fsck/images/badroot.img.gz b/e2fsck/images/badroot.img.gz
new file mode 100644 (file)
index 0000000..5724105
Binary files /dev/null and b/e2fsck/images/badroot.img.gz differ
diff --git a/e2fsck/images/badtable.img.gz b/e2fsck/images/badtable.img.gz
new file mode 100644 (file)
index 0000000..72934ce
Binary files /dev/null and b/e2fsck/images/badtable.img.gz differ
diff --git a/e2fsck/images/bbfile.img.gz b/e2fsck/images/bbfile.img.gz
new file mode 100644 (file)
index 0000000..155363a
Binary files /dev/null and b/e2fsck/images/bbfile.img.gz differ
diff --git a/e2fsck/images/bitmaps.img.gz b/e2fsck/images/bitmaps.img.gz
new file mode 100644 (file)
index 0000000..7eff4fc
Binary files /dev/null and b/e2fsck/images/bitmaps.img.gz differ
diff --git a/e2fsck/images/dirlink.img.gz b/e2fsck/images/dirlink.img.gz
new file mode 100644 (file)
index 0000000..7e1694a
Binary files /dev/null and b/e2fsck/images/dirlink.img.gz differ
diff --git a/e2fsck/images/dup.img.gz b/e2fsck/images/dup.img.gz
new file mode 100644 (file)
index 0000000..f901f19
Binary files /dev/null and b/e2fsck/images/dup.img.gz differ
diff --git a/e2fsck/images/dup2.img.gz b/e2fsck/images/dup2.img.gz
new file mode 100644 (file)
index 0000000..f5fcd37
Binary files /dev/null and b/e2fsck/images/dup2.img.gz differ
diff --git a/e2fsck/images/end-bitmap.img.gz b/e2fsck/images/end-bitmap.img.gz
new file mode 100644 (file)
index 0000000..b83478f
Binary files /dev/null and b/e2fsck/images/end-bitmap.img.gz differ
diff --git a/e2fsck/images/expand.img.gz b/e2fsck/images/expand.img.gz
new file mode 100644 (file)
index 0000000..0ea6729
Binary files /dev/null and b/e2fsck/images/expand.img.gz differ
diff --git a/e2fsck/images/lpf.img.gz b/e2fsck/images/lpf.img.gz
new file mode 100644 (file)
index 0000000..527c09b
Binary files /dev/null and b/e2fsck/images/lpf.img.gz differ
diff --git a/e2fsck/images/mke2fs2b.img.gz b/e2fsck/images/mke2fs2b.img.gz
new file mode 100644 (file)
index 0000000..9716a13
Binary files /dev/null and b/e2fsck/images/mke2fs2b.img.gz differ
diff --git a/e2fsck/images/noroot.img.gz b/e2fsck/images/noroot.img.gz
new file mode 100644 (file)
index 0000000..3e597f3
Binary files /dev/null and b/e2fsck/images/noroot.img.gz differ
diff --git a/e2fsck/images/test_script b/e2fsck/images/test_script
new file mode 100644 (file)
index 0000000..c0842ef
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# Test script for e2fsck
+#
+
+FSCK=../e2fsck
+SECOND_FSCK=$FSCK
+FSCK_OPT=-yft
+SECOND_FSCK_OPT=$FSCK_OPT
+
+#
+# Uncomment to test against original e2fsck
+#
+#FSCK=/u4/src/e2fsprogs-0.3c/e2fsck
+#FSCK_OPT=-af
+
+OUTFILE=test_script.log
+
+cp /dev/null $OUTFILE
+
+for i in *.img.gz
+do
+       echo -n "Testing $i...  "
+       echo "Testing $i..." >> $OUTFILE
+       gunzip < $i > /tmp/$i.$$
+       echo $FSCK $FSCK_OPT /tmp/$i.$$  >> $OUTFILE
+       $FSCK $FSCK_OPT /tmp/$i.$$  >> $OUTFILE 2>&1 
+       status=$?
+       echo Exit status is $status >> $OUTFILE
+       echo " "  >> $OUTFILE
+       echo -n "Exit status $status    "
+       echo Running e2fsck again.... >> $OUTFILE
+       echo $SECOND_FSCK $SECOND_FSCK_OPT /tmp/$i.$$ >> $OUTFILE
+       $SECOND_FSCK $SECOND_FSCK_OPT /tmp/$i.$$ >> $OUTFILE 2>&1 
+       status=$?
+       echo Exit status is $status >> $OUTFILE
+       echo Exit status $status
+       rm /tmp/$i.$$
+       echo "---------------------------------------------------" >> $OUTFILE
+done
+       
+       
diff --git a/e2fsck/images/test_script.log b/e2fsck/images/test_script.log
new file mode 100644 (file)
index 0000000..c583fe5
--- /dev/null
@@ -0,0 +1,1289 @@
+Testing baddir.img.gz...
+../e2fsck -yft /tmp/baddir.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Inode 13 is a zero length directory.  Clear? yes
+
+Pass 2: Checking directory structure
+Entry 'zero' in / (2) has deleted/unused inode 13.
+Clear? yes
+
+Directory inode 12, block 0, offset 0: directory corrupted
+Salvage? yes
+
+Missing '.' in directory inode 12.
+Fix? yes
+
+Missing '..' in directory inode 12.
+Fix? yes
+
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  2.354/ 0.000/ 0.320
+'..' in /block.h (12) is . (0), should be / (2).
+Fix? yes
+
+Pass 4: Check reference counts.
+Inode 12 has ref count 1, expecting 2.
+Set i_nlinks to count? yes
+
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Block bitmap differences: -22.  FIXED
+Free blocks count wrong (76, counted=77).  FIXED
+Inode bitmap differences: -13.  FIXED
+Free inodes count wrong for group #0 (19, counted=20).  FIXED
+Directories count wrong for group #0 (4, counted=3).  FIXED
+Free inodes count wrong (19, counted=20).  FIXED
+
+/tmp/baddir.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/baddir.img.gz.994: 12/32 files, 23/100 blocks
+Memory used: 74192, elapsed time:  3.648/ 0.020/ 0.590
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/baddir.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.369/ 0.010/ 0.280
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/baddir.img.gz.994: 12/32 files, 23/100 blocks
+Memory used: 78288, elapsed time:  2.638/ 0.030/ 0.520
+Exit status is 0
+---------------------------------------------------
+Testing badinode.img.gz...
+../e2fsck -yft /tmp/badinode.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Inode 12 (/motd) has a bad mode (0110444).
+Clear? yes
+
+i_fsize for inode 13 (/timings) is 4, should be zero.
+Clear i_fsize? yes
+
+i_file_acl for inode 13 (/timings) is 39, should be zero.
+Clear i_file_acl? yes
+
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.882/ 0.010/ 0.300
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Block bitmap differences: -25.  FIXED
+Free blocks count wrong for group 0 (76, counted=77).  FIXED
+Free blocks count wrong (76, counted=77).  FIXED
+Free inodes count wrong for group #0 (19, counted=20).  FIXED
+Free inodes count wrong (19, counted=20).  FIXED
+
+/tmp/badinode.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/badinode.img.gz.994: 12/32 files, 23/100 blocks
+Memory used: 78288, elapsed time:  3.171/ 0.040/ 0.550
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/badinode.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.380/ 0.000/ 0.300
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/badinode.img.gz.994: 12/32 files, 23/100 blocks
+Memory used: 78288, elapsed time:  2.659/ 0.010/ 0.560
+Exit status is 0
+---------------------------------------------------
+Testing badlkcnt.img.gz...
+../e2fsck -yft /tmp/badlkcnt.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+
+Deleted inode detected with non-zero link count.
+This is probably due to old ext2fs kernel code.  
+Fix inode(s)? yes
+
+Inode 13 is deleted w/ non-zero link_count.  CLEARED
+Inode 15 is deleted w/ non-zero link_count.  CLEARED
+Inode 16 is deleted w/ non-zero link_count.  CLEARED
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.935/ 0.030/ 0.270
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+
+/tmp/badlkcnt.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/badlkcnt.img.gz.994: 29/32 files, 32/100 blocks
+Memory used: 78288, elapsed time:  3.211/ 0.050/ 0.520
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/badlkcnt.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.382/ 0.010/ 0.280
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/badlkcnt.img.gz.994: 29/32 files, 32/100 blocks
+Memory used: 78288, elapsed time:  2.659/ 0.020/ 0.540
+Exit status is 0
+---------------------------------------------------
+Testing badroot.img.gz...
+../e2fsck -yft /tmp/badroot.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Root inode is not a directory.  Clear? yes
+
+Pass 2: Checking directory structure
+Entry '..' in ??? (11) has deleted/unused inode 2.
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.920/ 0.020/ 0.280
+Root inode not allocated.  Rellocate? yes
+
+Unconnected directory inode 11 (...)
+Connect to /lost+found? yes
+
+/lost+found not found.  Create? yes
+
+Pass 4: Check reference counts.
+Inode 11 has ref count 3, expecting 2.
+Set i_nlinks to count? yes
+
+Unattached inode 12
+Connect to /lost+found? yes
+
+Inode 12 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Free blocks count wrong for group 0 (77, counted=76).  FIXED
+Free blocks count wrong (77, counted=76).  FIXED
+Free inodes count wrong for group #0 (20, counted=19).  FIXED
+Directories count wrong for group #0 (2, counted=3).  FIXED
+Free inodes count wrong (20, counted=19).  FIXED
+
+/tmp/badroot.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/badroot.img.gz.994: 13/32 files, 24/100 blocks
+Memory used: 78288, elapsed time:  3.222/ 0.040/ 0.560
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/badroot.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.380/ 0.010/ 0.290
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/badroot.img.gz.994: 13/32 files, 24/100 blocks
+Memory used: 78288, elapsed time:  2.658/ 0.020/ 0.540
+Exit status is 0
+---------------------------------------------------
+Testing badtable.img.gz...
+../e2fsck -yft /tmp/badtable.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Warning: Bad block(s) found in filesystem-reserved blocks.
+Bad block 3 in group 0's block bitmap.  Relocate? yes
+
+Bad block 4 in group 0's inode bitmap.  Relocate? yes
+
+WARNING: Severe data loss possible!!!!
+Bad block 6 in group 0's inode table.  Relocate? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.939/ 0.020/ 0.280
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Block bitmap differences: -5 -7 +22 +23 +24 +25 +26 +27.  FIXED
+Free blocks count wrong for group 0 (78, counted=74).  FIXED
+Free blocks count wrong (78, counted=74).  FIXED
+
+/tmp/badtable.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/badtable.img.gz.994: 11/32 files, 26/100 blocks
+Memory used: 78288, elapsed time:  3.232/ 0.040/ 0.550
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/badtable.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.379/ 0.010/ 0.290
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/badtable.img.gz.994: 11/32 files, 26/100 blocks
+Memory used: 78288, elapsed time:  2.658/ 0.020/ 0.550
+Exit status is 0
+---------------------------------------------------
+Testing bbfile.img.gz...
+../e2fsck -yft /tmp/bbfile.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Duplicate blocks found... invoking duplicate block passes.
+Pass 1B: Rescan for duplicate/bad blocks
+Duplicate/bad block(s) in inode 2: 21
+Duplicate/bad block(s) in inode 11: 9 10 11 12 13 14 15 16 17 18 19 20
+Duplicate/bad block(s) in inode 12: 25 26
+Pass 1C: Scan directories for inodes with dup blocks.
+Pass 1D: Reconciling duplicate blocks
+(There are 3 inodes containing duplicate/bad blocks.)
+
+File /termcap (inode #12, mod time Sun Jan  2 03:29:13 1994) 
+  has 2 duplicate blocks, shared with 1 file:
+       <The bad blocks inode> (inode #1, mod time Sun Jan  2 03:32:04 1994)
+Clone duplicate/bad blocks? yes
+
+
+File /lost+found (inode #11, mod time Sun Jan  2 03:28:40 1994) 
+  has 12 duplicate blocks, shared with 1 file:
+       <The bad blocks inode> (inode #1, mod time Sun Jan  2 03:32:04 1994)
+Clone duplicate/bad blocks? yes
+
+
+File / (inode #2, mod time Sun Jan  2 03:29:13 1994) 
+  has 1 duplicate blocks, shared with 1 file:
+       <The bad blocks inode> (inode #1, mod time Sun Jan  2 03:32:04 1994)
+Clone duplicate/bad blocks? yes
+
+
+Warning: Bad block(s) found in filesystem-reserved blocks.
+Bad block 4 in group 0's inode bitmap.  Relocate? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  2.031/ 0.070/ 0.280
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Block bitmap differences: +22 +23 +24 +57.  FIXED
+Free blocks count wrong for group 0 (61, counted=42).  FIXED
+Free blocks count wrong (61, counted=42).  FIXED
+
+/tmp/bbfile.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/bbfile.img.gz.994: 12/32 files, 58/100 blocks
+Memory used: 78288, elapsed time:  3.322/ 0.100/ 0.530
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/bbfile.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Warning: Bad block(s) found in filesystem-reserved blocks.
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.374/ 0.000/ 0.300
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/bbfile.img.gz.994: 12/32 files, 58/100 blocks
+Memory used: 78288, elapsed time:  2.649/ 0.020/ 0.550
+Exit status is 0
+---------------------------------------------------
+Testing bitmaps.img.gz...
+../e2fsck -yft /tmp/bitmaps.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.811/ 0.020/ 0.290
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Block bitmap differences: +12 -20 +41 -50.  FIXED
+Inode bitmap differences: +11 -15.  FIXED
+
+/tmp/bitmaps.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/bitmaps.img.gz.994: 11/32 files, 22/100 blocks
+Memory used: 78288, elapsed time:  3.101/ 0.040/ 0.550
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/bitmaps.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.359/ 0.000/ 0.300
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/bitmaps.img.gz.994: 11/32 files, 22/100 blocks
+Memory used: 78288, elapsed time:  2.639/ 0.010/ 0.560
+Exit status is 0
+---------------------------------------------------
+Testing dirlink.img.gz...
+../e2fsck -yft /tmp/dirlink.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Entry 'quux' in /foo (12) is a link to directory /bar (13).
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  1.928/ 0.000/ 0.300
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+
+/tmp/dirlink.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/dirlink.img.gz.994: 13/32 files, 24/100 blocks
+Memory used: 74192, elapsed time:  3.203/ 0.010/ 0.560
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/dirlink.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  1.370/ 0.010/ 0.280
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/dirlink.img.gz.994: 13/32 files, 24/100 blocks
+Memory used: 74192, elapsed time:  2.649/ 0.030/ 0.530
+Exit status is 0
+---------------------------------------------------
+Testing dup.img.gz...
+../e2fsck -yft /tmp/dup.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Duplicate blocks found... invoking duplicate block passes.
+Pass 1B: Rescan for duplicate/bad blocks
+Duplicate/bad block(s) in inode 12: 25 26
+Duplicate/bad block(s) in inode 13: 25 26
+Pass 1C: Scan directories for inodes with dup blocks.
+Pass 1D: Reconciling duplicate blocks
+(There are 2 inodes containing duplicate/bad blocks.)
+
+File /motd (inode #13, mod time Mon Sep 20 23:19:20 1993) 
+  has 2 duplicate blocks, shared with 1 file:
+       /termcap (inode #12, mod time Mon Sep 20 23:19:14 1993)
+Clone duplicate/bad blocks? yes
+
+
+File /termcap (inode #12, mod time Mon Sep 20 23:19:14 1993) 
+  has 2 duplicate blocks, shared with 1 file:
+       /motd (inode #13, mod time Mon Sep 20 23:19:20 1993)
+Duplicated blocks already reassigned or cloned.
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.652/ 0.020/ 0.310
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Free blocks count wrong for group 0 (44, counted=60).  FIXED
+Free blocks count wrong (62, counted=60).  FIXED
+Padding at end of block bitmap is not set. Fix? yes
+
+
+/tmp/dup.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/dup.img.gz.994: 13/16 files, 40/100 blocks
+Memory used: 78288, elapsed time:  2.955/ 0.060/ 0.570
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/dup.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.370/ 0.000/ 0.300
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/dup.img.gz.994: 13/16 files, 40/100 blocks
+Memory used: 78288, elapsed time:  2.647/ 0.010/ 0.560
+Exit status is 0
+---------------------------------------------------
+Testing dup2.img.gz...
+../e2fsck -yft /tmp/dup2.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Duplicate blocks found... invoking duplicate block passes.
+Pass 1B: Rescan for duplicate/bad blocks
+Duplicate/bad block(s) in inode 12: 25 26
+Duplicate/bad block(s) in inode 13: 25 26 57 58
+Duplicate/bad block(s) in inode 14: 57 58
+Pass 1C: Scan directories for inodes with dup blocks.
+Pass 1D: Reconciling duplicate blocks
+(There are 3 inodes containing duplicate/bad blocks.)
+
+File /pass1.c (inode #14, mod time Tue Sep 21 00:28:37 1993) 
+  has 2 duplicate blocks, shared with 1 file:
+       /motd (inode #13, mod time Mon Sep 20 23:19:20 1993)
+Clone duplicate/bad blocks? yes
+
+
+File /motd (inode #13, mod time Mon Sep 20 23:19:20 1993) 
+  has 4 duplicate blocks, shared with 2 files:
+       /pass1.c (inode #14, mod time Tue Sep 21 00:28:37 1993)
+       /termcap (inode #12, mod time Mon Sep 20 23:19:14 1993)
+Clone duplicate/bad blocks? yes
+
+
+File /termcap (inode #12, mod time Mon Sep 20 23:19:14 1993) 
+  has 2 duplicate blocks, shared with 1 file:
+       /motd (inode #13, mod time Mon Sep 20 23:19:20 1993)
+Duplicated blocks already reassigned or cloned.
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.969/ 0.020/ 0.300
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Free blocks count wrong for group 0 (8, counted=22).  FIXED
+Free blocks count wrong (26, counted=22).  FIXED
+Padding at end of block bitmap is not set. Fix? yes
+
+
+/tmp/dup2.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/dup2.img.gz.994: 16/16 files, 78/100 blocks
+Memory used: 78288, elapsed time:  3.270/ 0.060/ 0.560
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/dup2.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.383/ 0.000/ 0.300
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/dup2.img.gz.994: 16/16 files, 78/100 blocks
+Memory used: 78288, elapsed time:  2.659/ 0.020/ 0.550
+Exit status is 0
+---------------------------------------------------
+Testing end-bitmap.img.gz...
+../e2fsck -yft /tmp/end-bitmap.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.998/ 0.010/ 0.300
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Free blocks count wrong for group 0 (44, counted=63).  FIXED
+Padding at end of block bitmap is not set. Fix? yes
+
+
+/tmp/end-bitmap.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/end-bitmap.img.gz.994: 12/16 files, 37/100 blocks
+Memory used: 78288, elapsed time:  3.285/ 0.030/ 0.560
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/end-bitmap.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 78288, elapsed time:  1.391/ 0.020/ 0.270
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/end-bitmap.img.gz.994: 12/16 files, 37/100 blocks
+Memory used: 78288, elapsed time:  2.668/ 0.030/ 0.530
+Exit status is 0
+---------------------------------------------------
+Testing expand.img.gz...
+../e2fsck -yft /tmp/expand.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Deleted inode 2 has zero dtime.
+Set dtime? yes
+
+Pass 2: Checking directory structure
+Entry '..' in /lost+found (11) has deleted/unused inode 2.
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  2.008/ 0.030/ 0.280
+Root inode not allocated.  Rellocate? yes
+
+Unconnected directory inode 11 (...)
+Connect to /lost+found? yes
+
+/lost+found not found.  Create? yes
+
+Pass 4: Check reference counts.
+Inode 11 has ref count 3, expecting 2.
+Set i_nlinks to count? yes
+
+Unattached inode 12
+Connect to /lost+found? yes
+
+Inode 12 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 13
+Connect to /lost+found? yes
+
+Inode 13 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 14
+Connect to /lost+found? yes
+
+Inode 14 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 15
+Connect to /lost+found? yes
+
+Inode 15 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 16
+Connect to /lost+found? yes
+
+Inode 16 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 17
+Connect to /lost+found? yes
+
+Inode 17 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 18
+Connect to /lost+found? yes
+
+Inode 18 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 19
+Connect to /lost+found? yes
+
+Inode 19 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 20
+Connect to /lost+found? yes
+
+Inode 20 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 21
+Connect to /lost+found? yes
+
+Inode 21 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 22
+Connect to /lost+found? yes
+
+Inode 22 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 23
+Connect to /lost+found? yes
+
+Inode 23 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 24
+Connect to /lost+found? yes
+
+Inode 24 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 25
+Connect to /lost+found? yes
+
+Inode 25 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 26
+Connect to /lost+found? yes
+
+Inode 26 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 27
+Connect to /lost+found? yes
+
+Inode 27 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 28
+Connect to /lost+found? yes
+
+Inode 28 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 29
+Connect to /lost+found? yes
+
+Inode 29 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 30
+Connect to /lost+found? yes
+
+Inode 30 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 31
+Connect to /lost+found? yes
+
+Inode 31 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 32
+Connect to /lost+found? yes
+
+Inode 32 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 33
+Connect to /lost+found? yes
+
+Inode 33 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 34
+Connect to /lost+found? yes
+
+Inode 34 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 35
+Connect to /lost+found? yes
+
+Inode 35 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 36
+Connect to /lost+found? yes
+
+Inode 36 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 37
+Connect to /lost+found? yes
+
+Inode 37 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 38
+Connect to /lost+found? yes
+
+Inode 38 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 39
+Connect to /lost+found? yes
+
+Inode 39 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 40
+Connect to /lost+found? yes
+
+Inode 40 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 41
+Connect to /lost+found? yes
+
+Inode 41 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 42
+Connect to /lost+found? yes
+
+Inode 42 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 43
+Connect to /lost+found? yes
+
+Inode 43 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 44
+Connect to /lost+found? yes
+
+Inode 44 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 45
+Connect to /lost+found? yes
+
+Inode 45 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 46
+Connect to /lost+found? yes
+
+Inode 46 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 47
+Connect to /lost+found? yes
+
+Inode 47 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 48
+Connect to /lost+found? yes
+
+Inode 48 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 49
+Connect to /lost+found? yes
+
+Inode 49 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 50
+Connect to /lost+found? yes
+
+Inode 50 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 51
+Connect to /lost+found? yes
+
+Inode 51 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 52
+Connect to /lost+found? yes
+
+Inode 52 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 53
+Connect to /lost+found? yes
+
+Inode 53 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 54
+Connect to /lost+found? yes
+
+Inode 54 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 55
+Connect to /lost+found? yes
+
+Inode 55 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 56
+Connect to /lost+found? yes
+
+Inode 56 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 57
+Connect to /lost+found? yes
+
+Inode 57 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 58
+Connect to /lost+found? yes
+
+Inode 58 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 59
+Connect to /lost+found? yes
+
+Inode 59 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 60
+Connect to /lost+found? yes
+
+Inode 60 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 61
+Connect to /lost+found? yes
+
+Inode 61 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 62
+Connect to /lost+found? yes
+
+Inode 62 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 63
+Connect to /lost+found? yes
+
+Inode 63 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 64
+Connect to /lost+found? yes
+
+Inode 64 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 65
+Connect to /lost+found? yes
+
+Inode 65 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 66
+Connect to /lost+found? yes
+
+Inode 66 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 67
+Connect to /lost+found? yes
+
+Inode 67 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 68
+Connect to /lost+found? yes
+
+Inode 68 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 69
+Connect to /lost+found? yes
+
+Inode 69 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 70
+Connect to /lost+found? yes
+
+Inode 70 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 71
+Connect to /lost+found? yes
+
+Inode 71 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 72
+Connect to /lost+found? yes
+
+Inode 72 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 73
+Connect to /lost+found? yes
+
+Inode 73 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 74
+Connect to /lost+found? yes
+
+Inode 74 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 75
+Connect to /lost+found? yes
+
+Inode 75 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 76
+Connect to /lost+found? yes
+
+Inode 76 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 77
+Connect to /lost+found? yes
+
+Inode 77 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 78
+Connect to /lost+found? yes
+
+Inode 78 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 79
+Connect to /lost+found? yes
+
+Inode 79 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 80
+Connect to /lost+found? yes
+
+Inode 80 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 81
+Connect to /lost+found? yes
+
+Inode 81 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 82
+Connect to /lost+found? yes
+
+Inode 82 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 83
+Connect to /lost+found? yes
+
+Inode 83 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 84
+Connect to /lost+found? yes
+
+Inode 84 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 85
+Connect to /lost+found? yes
+
+Inode 85 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 86
+Connect to /lost+found? yes
+
+Inode 86 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 87
+Connect to /lost+found? yes
+
+Inode 87 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 88
+Connect to /lost+found? yes
+
+Inode 88 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 89
+Connect to /lost+found? yes
+
+Inode 89 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 90
+Connect to /lost+found? yes
+
+Inode 90 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 91
+Connect to /lost+found? yes
+
+Inode 91 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 92
+Connect to /lost+found? yes
+
+Inode 92 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 93
+Connect to /lost+found? yes
+
+Inode 93 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 94
+Connect to /lost+found? yes
+
+No room in /lost+found; expand /lost+found? yes
+
+Inode 94 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 95
+Connect to /lost+found? yes
+
+Inode 95 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 96
+Connect to /lost+found? yes
+
+Inode 96 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 97
+Connect to /lost+found? yes
+
+Inode 97 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 98
+Connect to /lost+found? yes
+
+Inode 98 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 99
+Connect to /lost+found? yes
+
+Inode 99 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 100
+Connect to /lost+found? yes
+
+Inode 100 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 102
+Connect to /lost+found? yes
+
+Inode 102 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 103
+Connect to /lost+found? yes
+
+Inode 103 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 104
+Connect to /lost+found? yes
+
+Inode 104 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Block bitmap differences: -33.  FIXED
+Free blocks count wrong for group 0 (68, counted=67).  FIXED
+Free blocks count wrong (68, counted=67).  FIXED
+Free inodes count wrong for group #0 (1, counted=0).  FIXED
+Directories count wrong for group #0 (2, counted=3).  FIXED
+Free inodes count wrong (1, counted=0).  FIXED
+
+/tmp/expand.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/expand.img.gz.994: 104/104 files, 33/100 blocks
+Memory used: 74192, elapsed time:  3.652/ 0.210/ 0.740
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/expand.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  1.387/ 0.010/ 0.300
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/expand.img.gz.994: 104/104 files, 33/100 blocks
+Memory used: 74192, elapsed time:  2.668/ 0.020/ 0.560
+Exit status is 0
+---------------------------------------------------
+Testing lpf.img.gz...
+../e2fsck -yft /tmp/lpf.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+
+Deleted inode detected with non-zero link count.
+This is probably due to old ext2fs kernel code.  
+Fix inode(s)? yes
+
+Inode 11 is deleted w/ non-zero link_count.  CLEARED
+Inode 13 is deleted w/ non-zero link_count.  CLEARED
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  1.933/ 0.010/ 0.290
+Pass 4: Check reference counts.
+Unattached inode 14
+Connect to /lost+found? yes
+
+/lost+found not found.  Create? yes
+
+Inode 14 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Unattached inode 15
+Connect to /lost+found? yes
+
+Inode 15 has ref count 2, expecting 1.
+Set i_nlinks to count? yes
+
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Free blocks count wrong for group 0 (25, counted=38).  FIXED
+Free blocks count wrong (39, counted=38).  FIXED
+Free inodes count wrong for group #0 (2, counted=1).  FIXED
+Directories count wrong for group #0 (1, counted=2).  FIXED
+Free inodes count wrong (2, counted=1).  FIXED
+Padding at end of block bitmap is not set. Fix? yes
+
+
+/tmp/lpf.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/lpf.img.gz.994: 15/16 files, 62/100 blocks
+Memory used: 74192, elapsed time:  3.242/ 0.050/ 0.550
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/lpf.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  1.438/ 0.000/ 0.290
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/lpf.img.gz.994: 15/16 files, 62/100 blocks
+Memory used: 74192, elapsed time:  2.717/ 0.010/ 0.550
+Exit status is 0
+---------------------------------------------------
+Testing mke2fs2b.img.gz...
+../e2fsck -yft /tmp/mke2fs2b.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Root inode has dtime set (probably due to old mke2fs).  Fix? yes
+
+Note: /lost+found will probably be deleted as well, due to the mke2fs bug.
+Be sure to run mklost+found to recreate it after e2fsck finishes.
+
+
+Deleted inode detected with non-zero link count.
+This is probably due to old ext2fs kernel code.  
+Fix inode(s)? yes
+
+Inode 11 is deleted w/ non-zero link_count.  CLEARED
+Inode 15 is deleted w/ non-zero link_count.  CLEARED
+Pass 2: Checking directory structure
+Entry 'lost+found' in / (2) has deleted/unused inode 11.
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  1.911/ 0.000/ 0.300
+Pass 4: Check reference counts.
+Inode 2 has ref count 4, expecting 3.
+Set i_nlinks to count? yes
+
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Block bitmap differences: -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20.  FIXED
+Free blocks count wrong for group 0 (75, counted=87).  FIXED
+Free blocks count wrong (75, counted=87).  FIXED
+Inode bitmap differences: -11.  FIXED
+Free inodes count wrong for group #0 (17, counted=18).  FIXED
+Directories count wrong for group #0 (4, counted=3).  FIXED
+Free inodes count wrong (17, counted=18).  FIXED
+
+/tmp/mke2fs2b.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/mke2fs2b.img.gz.994: 14/32 files, 13/100 blocks
+Memory used: 74192, elapsed time:  3.208/ 0.020/ 0.570
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/mke2fs2b.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  1.364/ 0.010/ 0.280
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/mke2fs2b.img.gz.994: 14/32 files, 13/100 blocks
+Memory used: 74192, elapsed time:  2.637/ 0.030/ 0.530
+Exit status is 0
+---------------------------------------------------
+Testing noroot.img.gz...
+../e2fsck -yft /tmp/noroot.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+
+Deleted inode detected with non-zero link count.
+This is probably due to old ext2fs kernel code.  
+Fix inode(s)? yes
+
+Inode 15 is deleted w/ non-zero link_count.  CLEARED
+Pass 2: Checking directory structure
+Entry '..' in /lost+found (11) has deleted/unused inode 2.
+Clear? yes
+
+Entry '..' in /foo (12) has deleted/unused inode 2.
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  1.951/ 0.030/ 0.280
+Root inode not allocated.  Rellocate? yes
+
+Unconnected directory inode 11 (...)
+Connect to /lost+found? yes
+
+/lost+found not found.  Create? yes
+
+Unconnected directory inode 12 (...)
+Connect to /lost+found? yes
+
+Pass 4: Check reference counts.
+Inode 11 has ref count 3, expecting 2.
+Set i_nlinks to count? yes
+
+Inode 12 has ref count 4, expecting 3.
+Set i_nlinks to count? yes
+
+Pass 5: Checking group summary information.
+Fix summary information? yes
+
+Free blocks count wrong for group 0 (75, counted=74).  FIXED
+Free blocks count wrong (75, counted=74).  FIXED
+Free inodes count wrong for group #0 (17, counted=16).  FIXED
+Directories count wrong for group #0 (4, counted=5).  FIXED
+Free inodes count wrong (17, counted=16).  FIXED
+
+/tmp/noroot.img.gz.994: ***** FILE SYSTEM WAS MODIFIED *****
+/tmp/noroot.img.gz.994: 16/32 files, 26/100 blocks
+Memory used: 74192, elapsed time:  3.259/ 0.050/ 0.560
+Exit status is 1
+Running e2fsck again....
+../e2fsck -yft /tmp/noroot.img.gz.994
+e2fsck 0.5, 28-Mar-94 for EXT2 FS 0.5, 94/03/10
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Peak memory: Memory used: 74192, elapsed time:  1.360/ 0.000/ 0.290
+Pass 4: Check reference counts.
+Pass 5: Checking group summary information.
+/tmp/noroot.img.gz.994: 16/32 files, 26/100 blocks
+Memory used: 74192, elapsed time:  2.638/ 0.010/ 0.550
+Exit status is 0
+---------------------------------------------------
diff --git a/e2fsck/malloc.h b/e2fsck/malloc.h
new file mode 100644 (file)
index 0000000..3e46718
--- /dev/null
@@ -0,0 +1,231 @@
+/* Declarations for `malloc' and friends.
+   Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+                 Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef _MALLOC_H
+
+#define _MALLOC_H      1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef __P
+#define        __P(args)       args
+#undef __ptr_t
+#define        __ptr_t         void *
+#else /* Not C++ or ANSI C.  */
+#undef __P
+#define        __P(args)       ()
+#undef const
+#define        const
+#undef __ptr_t
+#define        __ptr_t         char *
+#endif /* C++ or ANSI C.  */
+
+#ifndef        NULL
+#define        NULL    0
+#endif
+
+#ifdef __STDC__
+#include <stddef.h>
+#else
+#undef size_t
+#define        size_t          unsigned int
+#undef ptrdiff_t
+#define        ptrdiff_t       int
+#endif
+
+
+/* Allocate SIZE bytes of memory.  */
+extern __ptr_t malloc __P ((size_t __size));
+/* Re-allocate the previously allocated block
+   in __ptr_t, making the new block SIZE bytes long.  */
+extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size));
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0.  */
+extern __ptr_t calloc __P ((size_t __nmemb, size_t __size));
+/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
+extern void free __P ((__ptr_t __ptr));
+
+/* Allocate SIZE bytes allocated to ALIGNMENT bytes.  */
+extern __ptr_t memalign __P ((size_t __alignment, size_t __size));
+
+/* Allocate SIZE bytes on a page boundary.  */
+extern __ptr_t valloc __P ((size_t __size));
+
+
+#ifdef _MALLOC_INTERNAL
+
+#include <stdio.h>             /* Harmless, gets __GNU_LIBRARY__ defined.  */
+
+#if    defined(__GNU_LIBRARY__) || defined(STDC_HEADERS) || defined(USG)
+#include <string.h>
+#else
+#ifndef memset
+#define        memset(s, zero, n)      bzero ((s), (n))
+#endif
+#ifndef memcpy
+#define        memcpy(d, s, n)         bcopy ((s), (d), (n))
+#endif
+#endif
+
+
+#if    defined(__GNU_LIBRARY__) || defined(__STDC__)
+#include <limits.h>
+#else
+#define        CHAR_BIT        8
+#endif
+
+/* The allocator divides the heap into blocks of fixed size; large
+   requests receive one or more whole blocks, and small requests
+   receive a fragment of a block.  Fragment sizes are powers of two,
+   and all fragments of a block are the same size.  When all the
+   fragments in a block have been freed, the block itself is freed.  */
+#define INT_BIT                (CHAR_BIT * sizeof(int))
+#define BLOCKLOG       (INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE      (1 << BLOCKLOG)
+#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* Determine the amount of memory spanned by the initial heap table
+   (not an absolute limit).  */
+#define HEAP           (INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+   memory before they will be returned to the system.  */
+#define FINAL_FREE_BLOCKS      8
+
+/* Data structure giving per-block information.  */
+typedef union
+  {
+    /* Heap information for a busy block.  */
+    struct
+      {
+       /* Zero for a large block, or positive giving the
+          logarithm to the base two of the fragment size.  */
+       int type;
+       union
+         {
+           struct
+             {
+               size_t nfree;   /* Free fragments in a fragmented block.  */
+               size_t first;   /* First free fragment of the block.  */
+             } frag;
+           /* Size (in blocks) of a large cluster.  */
+           size_t size;
+         } info;
+      } busy;
+    /* Heap information for a free block
+       (that may be the first of a free cluster).  */
+    struct
+      {
+       size_t size;            /* Size (in blocks) of a free cluster.  */
+       size_t next;            /* Index of next free cluster.  */
+       size_t prev;            /* Index of previous free cluster.  */
+      } free;
+  } malloc_info;
+
+/* Pointer to first block of the heap.  */
+extern char *_heapbase;
+
+/* Table indexed by block number giving per-block information.  */
+extern malloc_info *_heapinfo;
+
+/* Address to block number and vice versa.  */
+#define BLOCK(A)       (((char *) (A) - _heapbase) / BLOCKSIZE + 1)
+#define ADDRESS(B)     ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase))
+
+/* Current search index for the heap table.  */
+extern size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+extern size_t _heaplimit;
+
+/* Doubly linked lists of free fragments.  */
+struct list
+  {
+    struct list *next;
+    struct list *prev;
+  };
+
+/* Free list headers for each fragment size.  */
+extern struct list _fraghead[];
+
+/* List of blocks allocated with `memalign' (or `valloc').  */
+struct alignlist
+  {
+    struct alignlist *next;
+    __ptr_t aligned;           /* The address that memaligned returned.  */
+    __ptr_t exact;             /* The address that malloc returned.  */
+  };
+extern struct alignlist *_aligned_blocks;
+
+/* Instrumentation.  */
+extern size_t _chunks_used;
+extern size_t _bytes_used;
+extern size_t _chunks_free;
+extern size_t _bytes_free;
+
+/* Internal version of `free' used in `morecore' (malloc.c). */
+extern void _free_internal __P ((__ptr_t __ptr));
+
+#endif /* _MALLOC_INTERNAL.  */
+
+/* Underlying allocation function; successive calls should
+   return contiguous pieces of memory.  */
+extern __ptr_t (*__morecore) __P ((ptrdiff_t __size));
+
+/* Default value of `__morecore'.  */
+extern __ptr_t __default_morecore __P ((ptrdiff_t __size));
+
+/* Nonzero if `malloc' has been called and done its initialization.  */
+extern int __malloc_initialized;
+
+/* Hooks for debugging versions.  */
+extern void (*__free_hook) __P ((__ptr_t __ptr));
+extern __ptr_t (*__malloc_hook) __P ((size_t __size));
+extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Activate a standard collection of debugging hooks.  */
+extern void mcheck __P ((void (*__func) __P ((void))));
+
+/* Activate a standard collection of tracing hooks.  */
+extern void mtrace __P ((void));
+
+/* Statistics available to the user.  */
+struct mstats
+  {
+    size_t bytes_total;                /* Total size of the heap. */
+    size_t chunks_used;                /* Chunks allocated by the user. */
+    size_t bytes_used;         /* Byte total of user-allocated chunks. */
+    size_t chunks_free;                /* Chunks in the free list. */
+    size_t bytes_free;         /* Byte total of chunks in the free list. */
+  };
+
+/* Pick up the current statistics. */
+extern struct mstats mstats __P ((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* malloc.h  */
diff --git a/e2fsck/mtrace.awk b/e2fsck/mtrace.awk
new file mode 100644 (file)
index 0000000..7e96b8a
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/awk -f
+#
+#  Awk program to analyze mtrace.c output.
+#
+$1 == "+"      { if (allocated[$2] != "")
+                   print "+", $2, "Alloc", NR, "duplicate:", allocated[$2];
+                 else
+                   allocated[$2] = $3;
+               }
+$1 == "-"      { if (allocated[$2] != "") {
+                   allocated[$2] = "";
+                   if (allocated[$2] != "")
+                       print "DELETE FAILED", $2, allocated[$2];
+                 } else
+                   print "-", $2, "Free", NR, "was never alloc'd";
+               }
+$1 == "<"      { if (allocated[$2] != "")
+                   allocated[$2] = "";
+                 else
+                   print "-", $2, "Realloc", NR, "was never alloc'd";
+               }
+$1 == ">"      { if (allocated[$2] != "")
+                   print "+", $2, "Realloc", NR, "duplicate:", allocated[$2];
+                 else
+                   allocated[$2] = $3;
+               }
+
+# Ignore "= Start"
+$1 == "="      { }
+# Ignore failed realloc attempts for now
+$1 == "!"      { }
+
+
+END            { for (x in allocated) 
+                   if (allocated[x] != "")
+                     print "+", x, allocated[x];
+               }
diff --git a/e2fsck/mtrace.c b/e2fsck/mtrace.c
new file mode 100644 (file)
index 0000000..8553a64
--- /dev/null
@@ -0,0 +1,158 @@
+/* More debugging hooks for `malloc'.
+   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+                Written April 2, 1991 by John Gilmore of Cygnus Support.
+                Based on mcheck.c by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef        _MALLOC_INTERNAL
+#define        _MALLOC_INTERNAL
+#include "./malloc.h"
+#endif
+
+#include <stdio.h>
+
+#ifndef        __GNU_LIBRARY__
+extern char *getenv ();
+#else
+#include <stdlib.h>
+#endif
+
+static FILE *mallstream;
+static char mallenv[]= "MALLOC_TRACE";
+static char mallbuf[BUFSIZ];   /* Buffer for the output.  */
+
+/* Address to breakpoint on accesses to... */
+__ptr_t mallwatch;
+
+/* Old hook values.  */
+static void (*tr_old_free_hook) __P ((__ptr_t ptr));
+static __ptr_t (*tr_old_malloc_hook) __P ((size_t size));
+static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr, size_t size));
+
+/*
+ * Added by TYT, 10/10/93 --- so that we can print 
+ */
+FILE *malloc_get_mallstream()
+{
+       return mallstream;
+}
+
+/* This function is called when the block being alloc'd, realloc'd, or
+   freed has an address matching the variable "mallwatch".  In a debugger,
+   set "mallwatch" to the address of interest, then put a breakpoint on
+   tr_break.  */
+
+void tr_break __P ((void));
+void
+tr_break ()
+{
+}
+
+static void tr_freehook __P ((__ptr_t));
+static void
+tr_freehook (ptr)
+     __ptr_t ptr;
+{
+  fprintf (mallstream, "- %p\n", ptr); /* Be sure to print it first.  */
+  if (ptr == mallwatch)
+    tr_break ();
+  __free_hook = tr_old_free_hook;
+  free (ptr);
+  __free_hook = tr_freehook;
+}
+
+static __ptr_t tr_mallochook __P ((size_t));
+static __ptr_t
+tr_mallochook (size)
+     size_t size;
+{
+  __ptr_t hdr;
+
+  __malloc_hook = tr_old_malloc_hook;
+  hdr = (__ptr_t) malloc (size);
+  __malloc_hook = tr_mallochook;
+
+  /* We could be printing a NULL here; that's OK.  */
+  fprintf (mallstream, "+ %p %d\n", hdr, size);
+
+  if (hdr == mallwatch)
+    tr_break ();
+
+  return hdr;
+}
+
+static __ptr_t tr_reallochook __P ((__ptr_t, size_t));
+static __ptr_t
+tr_reallochook (ptr, size)
+     __ptr_t ptr;
+     size_t size;
+{
+  __ptr_t hdr;
+
+  if (ptr == mallwatch)
+    tr_break ();
+
+  __free_hook = tr_old_free_hook;
+  __malloc_hook = tr_old_malloc_hook;
+  __realloc_hook = tr_old_realloc_hook;
+  hdr = (__ptr_t) realloc (ptr, size);
+  __free_hook = tr_freehook;
+  __malloc_hook = tr_mallochook;
+  __realloc_hook = tr_reallochook;
+  if (hdr == NULL)
+    /* Failed realloc.  */
+    fprintf (mallstream, "! %p %d\n", ptr, size);
+  else
+    fprintf (mallstream, "< %p\n> %p %d\n", ptr, hdr, size);
+
+  if (hdr == mallwatch)
+    tr_break ();
+
+  return hdr;
+}
+
+/* We enable tracing if either the environment variable MALLOC_TRACE
+   is set, or if the variable mallwatch has been patched to an address
+   that the debugging user wants us to stop on.  When patching mallwatch,
+   don't forget to set a breakpoint on tr_break!  */
+
+void
+mtrace ()
+{
+  char *mallfile;
+
+  mallfile = getenv (mallenv);
+  if (mallfile != NULL || mallwatch != NULL)
+    {
+      mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
+      if (mallstream != NULL)
+       {
+         /* Be sure it doesn't malloc its buffer!  */
+         setbuf (mallstream, mallbuf);
+         fprintf (mallstream, "= Start\n");
+         tr_old_free_hook = __free_hook;
+         __free_hook = tr_freehook;
+         tr_old_malloc_hook = __malloc_hook;
+         __malloc_hook = tr_mallochook;
+         tr_old_realloc_hook = __realloc_hook;
+         __realloc_hook = tr_reallochook;
+       }
+    }
+}
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
new file mode 100644 (file)
index 0000000..2f23b9d
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+ * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ * 
+ * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
+ * and applies the following tests to each inode:
+ *
+ *     - The mode field of the inode must be legal.
+ *     - The size and block count fields of the inode are correct.
+ *     - A data block must not be used by another inode
+ *
+ * Pass 1 also gathers the collects the following information:
+ *
+ *     - A bitmap of which inodes are in use.          (inode_used_map)
+ *     - A bitmap of which inodes are directories.     (inode_dir_map)
+ *     - A bitmap of which inodes have bad fields.     (inode_bad_map)
+ *     - A bitmap of which blocks are in use.          (block_found_map)
+ *     - A bitmap of which blocks are in use by two inodes     (block_dup_map)
+ *     - The data blocks of the directory inodes.      (dir_map)
+ *
+ * Pass 1 is designed to stash away enough information so that the
+ * other passes should not need to read in the inode information
+ * during the normal course of a filesystem check.  (Althogh if an
+ * inconsistency is detected, other passes may need to read in an
+ * inode to fix it.)
+ *
+ * Note that pass 1B will be invoked if there are any duplicate blocks
+ * found.
+ */
+
+#include <time.h>
+
+#include <et/com_err.h>
+#include "e2fsck.h"
+
+/* Files counts */
+int fs_directory_count = 0;
+int fs_regular_count = 0;
+int fs_blockdev_count = 0;
+int fs_chardev_count = 0;
+int fs_links_count = 0;
+int fs_symlinks_count = 0;
+int fs_fast_symlinks_count = 0;
+int fs_fifo_count = 0;
+int fs_total_count = 0;
+int fs_badblocks_count = 0;
+int fs_sockets_count = 0;
+
+char * inode_used_map = 0;     /* Inodes which are in use */
+char * inode_bad_map = 0;      /* Inodes which are bad in some way */
+char * inode_dir_map = 0;      /* Inodes which are directories */
+
+char * block_found_map = 0;
+char * block_dup_map = 0;
+static char * bad_fs_block_map = 0;
+
+static int fix_link_count = -1;
+
+unsigned short * inode_link_info = NULL;
+
+static int process_block(ext2_filsys fs, blk_t *blocknr,
+                        int    blockcnt, void  *private);
+static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
+                            int blockcnt, void *private);
+static int process_fs_bad_block(ext2_filsys fs, blk_t *block_nr,
+                               int blockcnt, void *private);
+static void check_blocks(ext2_filsys fs, ino_t ino, struct ext2_inode *inode,
+                        char *block_buf);
+static void mark_table_blocks(ext2_filsys fs);
+static errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino);
+static errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks);
+static void alloc_bad_map(ext2_filsys fs);
+static void handle_fs_bad_blocks(ext2_filsys fs, char *block_buf);
+static void process_inodes(ext2_filsys fs, char *block_buf);
+static int process_inode_cmp(const void *a, const void *b);
+static int dir_block_cmp(const void *a, const void *b);
+
+struct process_block_struct {
+       ino_t   ino;
+       int     is_dir;
+       int     num_blocks;
+       int     last_block;
+       int     fix;
+};
+
+struct process_inode_block {
+       ino_t   ino;
+       struct ext2_inode inode;
+};
+
+/*
+ * For pass1_check_directory and pass1_get_blocks
+ */
+ino_t stashed_ino;
+struct ext2_inode *stashed_inode;
+
+/*
+ * For the inodes to process list.
+ */
+static struct process_inode_block *inodes_to_process;
+static int process_inode_count;
+int process_inode_size = 128;
+
+/*
+ * For the directory blocks list.
+ */
+struct dir_block_struct *dir_blocks = 0;
+int    dir_block_count = 0;
+int    dir_block_size = 0;
+
+void pass1(ext2_filsys fs)
+{
+       ino_t   ino;
+       struct ext2_inode inode;
+       ext2_inode_scan scan;
+       char            *block_buf;
+       errcode_t       retval;
+       struct resource_track   rtrack;
+       
+       init_resource_track(&rtrack);
+       
+       if (!preen)
+               printf("Pass 1: Checking inodes, blocks, and sizes\n");
+
+#ifdef MTRACE
+       mtrace_print("Pass 1");
+#endif
+
+       /*
+        * Allocate bitmaps structures
+        */
+       retval = ext2fs_allocate_inode_bitmap(fs, &inode_used_map);
+       if (retval) {
+               com_err("ext2fs_allocate_inode_bitmap", retval,
+                       "while allocating inode_used_map");
+               fatal_error(0);
+       }
+       retval = ext2fs_allocate_inode_bitmap(fs, &inode_dir_map);
+       if (retval) {
+               com_err("ext2fs_allocate_inode_bitmap", retval,
+                       "while allocating inode_dir_map");
+               fatal_error(0);
+       }
+       retval = ext2fs_allocate_block_bitmap(fs, &block_found_map);
+       if (retval) {
+               com_err("ext2fs_allocate_block_bitmap", retval,
+                       "while allocating block_found_map");
+               fatal_error(0);
+       }
+       inode_link_info = allocate_memory((fs->super->s_inodes_count + 1) *
+                                         sizeof(unsigned short),
+                                         "inode link count array");
+       inodes_to_process = allocate_memory(process_inode_size *
+                                           sizeof(struct process_inode_block),
+                                           "array of inodes to process");
+       process_inode_count = 0;
+
+       dir_block_size = get_num_dirs(fs) * 4;
+       dir_block_count = 0;
+       dir_blocks = allocate_memory(sizeof(struct dir_block_struct) *
+                                    dir_block_size,
+                                    "directory block information");
+
+       mark_table_blocks(fs);
+       block_buf = allocate_memory(fs->blocksize * 3, "block interate buffer");
+       fs->get_blocks = pass1_get_blocks;
+       fs->check_directory = pass1_check_directory;
+       ehandler_operation("doing inode scan");
+       retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan);
+       if (retval) {
+               com_err(program_name, retval, "while opening inode scan");
+               fatal_error(0);
+       }
+       retval = ext2fs_get_next_inode(scan, &ino, &inode);
+       if (retval) {
+               com_err(program_name, retval, "while starting inode scan");
+               fatal_error(0);
+       }
+       stashed_inode = &inode;
+       while (ino) {
+               stashed_ino = ino;
+               inode_link_info[ino] = inode.i_links_count;
+               if (ino == EXT2_BAD_INO) {
+                       struct process_block_struct pb;
+                       
+                       pb.ino = EXT2_BAD_INO;
+                       pb.num_blocks = pb.last_block = 0;
+                       pb.is_dir = 0;
+                       pb.fix = -1;
+                       retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
+                                                     process_bad_block, &pb);
+                       if (retval)
+                               com_err(program_name, retval, "while calling e2fsc_block_interate in pass 1");
+
+                       ext2fs_mark_inode_bitmap(fs, inode_used_map, ino);
+                       goto next;
+               }
+               if (ino == EXT2_ROOT_INO) {
+                       /*
+                        * Make sure the root inode is a directory; if
+                        * not, offer to clear it.  It will be
+                        * regnerated in pass #3.
+                        */
+                       if (!S_ISDIR(inode.i_mode)) {
+                               printf("Root inode is not a directory.  ");
+                               preenhalt();
+                               if (ask("Clear", 1)) {
+                                       inode.i_dtime = time(0);
+                                       inode.i_links_count = 0;
+                                       ext2fs_write_inode(fs, ino, &inode);
+                               } else 
+                                       ext2fs_unmark_valid(fs);
+                       }
+                       /*
+                        * If dtime is set, offer to clear it.  mke2fs
+                        * version 0.2b created filesystems with the
+                        * dtime field set for the root and lost+found
+                        * directories.  We won't worry about
+                        * /lost+found, since that can be regenerated
+                        * easily.  But we will fix the root directory
+                        * as a special case.
+                        */
+                       if (inode.i_dtime && inode.i_links_count) {
+                               if (ask("Root inode has dtime set "
+                                       "(probably due to old mke2fs).  Fix",
+                                       1)) {
+                                       inode.i_dtime = 0;
+                                       ext2fs_write_inode(fs, ino, &inode);
+                                       printf("Note: /lost+found will "
+                                              "probably be deleted as well, "
+                                              "due to the mke2fs bug.\n"
+                                              "Be sure to run mklost+found "
+                                              "to recreate it after e2fsck "
+                                              "finishes.\n\n");
+                               } else
+                                       ext2fs_unmark_valid(fs);
+                       }
+               }
+               if ((ino != EXT2_ROOT_INO) && (ino < EXT2_FIRST_INO)) {
+                       ext2fs_mark_inode_bitmap(fs, inode_used_map, ino);
+                       check_blocks(fs, ino, &inode, block_buf);
+                       goto next;
+               }
+               /*
+                * This code assumes that deleted inodes have
+                * i_links_count set to 0.  
+                */
+               if (!inode.i_links_count) {
+                       if (!inode.i_dtime && inode.i_mode) {
+                               printf("Deleted inode %ld has zero dtime.\n",
+                                      ino);
+                               if (ask("Set dtime", 1)) {
+                                       inode.i_dtime = time(0);
+                                       ext2fs_write_inode(fs, ino, &inode);
+                               } else
+                                       ext2fs_unmark_valid(fs);
+                       }
+                       goto next;
+               }
+               /*
+                * 0.3c ext2fs code didn't clear i_links_count for
+                * deleted files.  Oops.
+                * 
+                * In the future, when the new ext2fs behavior is the
+                * norm, we may want to handle the case of a non-zero
+                * i_links_count and non-zero dtime by clearing dtime
+                * and assuming the inode is in use, instead of
+                * assuming the inode is not in use.
+                */
+               if (inode.i_dtime) {
+                       if (fix_link_count == -1) {
+                               printf("\nDeleted inode detected with non-zero link count.\n");
+                               printf("This is probably due to old ext2fs kernel code.  \n");
+                               fix_link_count = ask("Fix inode(s)", 1);
+                       }
+                       printf("Inode %ld is deleted w/ non-zero link_count.  %s\n",
+                              ino, clear_msg[fix_link_count]);
+                       if (fix_link_count) {
+                               inode.i_links_count = 0;
+                               ext2fs_write_inode(fs, ino, &inode);
+                       } else
+                               ext2fs_unmark_valid(fs);
+                       goto next;
+               }
+               
+               ext2fs_mark_inode_bitmap(fs, inode_used_map, ino);
+               if (inode.i_faddr || inode.i_frag || inode.i_fsize ||
+                   inode.i_file_acl || inode.i_dir_acl) {
+                       if (!inode_bad_map)
+                               alloc_bad_map(fs);
+                       ext2fs_mark_inode_bitmap(fs, inode_bad_map, ino);
+               }
+               
+               if (S_ISDIR(inode.i_mode)) {
+                       ext2fs_mark_inode_bitmap(fs, inode_dir_map, ino);
+                       add_dir_info(fs, ino, 0, &inode);
+                       fs_directory_count++;
+               } else if (S_ISREG (inode.i_mode))
+                       fs_regular_count++;
+               else if (S_ISCHR (inode.i_mode))
+                       fs_chardev_count++;
+               else if (S_ISBLK (inode.i_mode))
+                       fs_blockdev_count++;
+               else if (S_ISLNK (inode.i_mode)) {
+                       fs_symlinks_count++;
+                       if (!inode.i_blocks)
+                               fs_fast_symlinks_count++;
+               }
+               else if (S_ISFIFO (inode.i_mode))
+                       fs_fifo_count++;
+               else if (S_ISSOCK (inode.i_mode))
+                       fs_sockets_count++;
+               else {
+                       if (!inode_bad_map)
+                               alloc_bad_map(fs);
+                       ext2fs_mark_inode_bitmap(fs, inode_bad_map, ino);
+               }
+               if (inode.i_block[EXT2_IND_BLOCK] ||
+                   inode.i_block[EXT2_DIND_BLOCK] ||
+                   inode.i_block[EXT2_TIND_BLOCK]) {
+                       inodes_to_process[process_inode_count].ino = ino;
+                       inodes_to_process[process_inode_count].inode = inode;
+                       process_inode_count++;
+               } else 
+                       check_blocks(fs, ino, &inode, block_buf);
+               inode_link_info[ino] = inode.i_links_count;
+
+               if (process_inode_count >= process_inode_size)
+                       process_inodes(fs, block_buf);
+       next:
+               retval = ext2fs_get_next_inode(scan, &ino, &inode);
+               if (retval) {
+                       com_err(program_name, retval,
+                               "while doing inode scan");
+                       fatal_error(0);
+               }
+       }
+       process_inodes(fs, block_buf);
+       ext2fs_close_inode_scan(scan);
+       ehandler_operation(0);
+
+       qsort(dir_blocks, dir_block_count, sizeof(struct dir_block_struct),
+             dir_block_cmp);
+
+       if (block_dup_map) {
+               if (preen) {
+                       printf("Duplicate or bad blocks in use!\n");
+                       preenhalt();
+               }
+               pass1_dupblocks(fs, block_buf);
+       }
+       fs->get_blocks = 0;
+       fs->check_directory = 0;
+       free(inodes_to_process);
+       if (bad_fs_block_map) {
+               handle_fs_bad_blocks(fs, block_buf);
+               free(bad_fs_block_map);
+       }
+       free(block_buf);
+
+       if (tflag > 1) {
+               printf("Pass 1: ");
+               print_resource_track(&rtrack);
+       }
+}
+
+/*
+ * Process the inodes in the "inodes to process" list.
+ */
+static void process_inodes(ext2_filsys fs, char *block_buf)
+{
+       int                     i;
+       struct ext2_inode       *old_stashed_inode;
+       ino_t                   ino;
+       const char              *old_operation;
+       char                    buf[80];
+
+#if 0
+       printf("process_inodes: ");
+#endif
+       old_operation = ehandler_operation(0);
+       old_stashed_inode = stashed_inode;
+       qsort(inodes_to_process, process_inode_count,
+                     sizeof(struct process_inode_block), process_inode_cmp);
+       for (i=0; i < process_inode_count; i++) {
+               stashed_inode = &inodes_to_process[i].inode;
+               ino = inodes_to_process[i].ino;
+               stashed_ino = ino;
+#if 0
+               printf("%d ", ino);
+#endif
+               sprintf(buf, "reading indirect blocks of inode %ld", ino);
+               ehandler_operation(buf);
+               check_blocks(fs, ino, stashed_inode, block_buf);
+               
+       }
+       stashed_inode = old_stashed_inode;
+       process_inode_count = 0;
+#if 0
+       printf("\n");
+#endif
+       ehandler_operation(old_operation);
+}
+
+static int process_inode_cmp(const void *a, const void *b)
+{
+       const struct process_inode_block *ib_a =
+               (const struct process_inode_block *) a;
+       const struct process_inode_block *ib_b =
+               (const struct process_inode_block *) b;
+
+       return (ib_a->inode.i_block[EXT2_IND_BLOCK] -
+               ib_b->inode.i_block[EXT2_IND_BLOCK]);
+}
+
+static int dir_block_cmp(const void *a, const void *b)
+{
+       const struct dir_block_struct *db_a =
+               (const struct dir_block_struct *) a;
+       const struct dir_block_struct *db_b =
+               (const struct dir_block_struct *) b;
+
+       return (db_a->blk - db_b->blk);
+}
+
+/*
+ * This procedure will allocate the inode bad map table
+ */
+static void alloc_bad_map(ext2_filsys fs)
+{
+       errcode_t       retval;
+       
+       retval = ext2fs_allocate_inode_bitmap(fs, &inode_bad_map);
+       if (retval) {
+               com_err("ext2fs_allocate_inode_bitmap", retval,
+                       "while allocating inode_bad_map");
+               fatal_error(0);
+       }
+}
+
+/*
+ * Marks a block as in use, setting the dup_map if it's been set
+ * already.  Called by process_block and process_bad_block.
+ */
+static void mark_block_used(ext2_filsys fs, blk_t block)
+{
+       errcode_t       retval;
+       
+       if (ext2fs_test_block_bitmap(fs, block_found_map, block)) {
+               if (!block_dup_map) {
+                       retval = ext2fs_allocate_block_bitmap(fs,
+                                                             &block_dup_map);
+                       if (retval) {
+                               com_err("ext2fs_allocate_block_bitmap", retval,
+                                       "while allocating block_dup_map");
+                               fatal_error(0);
+                       }
+               }
+               ext2fs_mark_block_bitmap(fs, block_dup_map, block);
+       } else {
+               ext2fs_mark_block_bitmap(fs, block_found_map, block);
+       }
+}
+
+/*
+ * This subroutine is called on each inode to account for all of the
+ * blocks used by that inode.
+ */
+static void check_blocks(ext2_filsys fs, ino_t ino, struct ext2_inode *inode,
+                        char *block_buf)
+{
+       struct process_block_struct pb;
+       errcode_t       retval;
+       
+       if (!inode_has_valid_blocks(inode))
+               return;
+       
+       pb.ino = ino;
+       pb.num_blocks = pb.last_block = 0;
+       pb.is_dir = S_ISDIR(inode->i_mode);
+       pb.fix = -1;
+       retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
+                                     process_block, &pb);
+       if (retval)
+               com_err(program_name, retval,
+                       "while calling ext2fs_block_iterate in check_blocks");
+
+       pb.num_blocks *= (fs->blocksize / 512);
+#if 0
+       printf("inode %d, i_size = %d, last_block = %d, i_blocks=%d, num_blocks = %d\n",
+              ino, inode->i_size, pb.last_block, inode->i_blocks,
+              pb.num_blocks);
+#endif
+       if (!pb.num_blocks && pb.is_dir) {
+               printf("Inode %ld is a zero length directory.  ", ino);
+               if (ask("Clear", 1)) {
+                       inode->i_links_count = 0;
+                       inode->i_dtime = time(0);
+                       ext2fs_write_inode(fs, ino, inode);
+                       ext2fs_unmark_inode_bitmap(fs, inode_dir_map, ino);
+                       ext2fs_unmark_inode_bitmap(fs, inode_used_map, ino);
+                       fs_directory_count--;
+               } else
+                       ext2fs_unmark_valid(fs);
+       }
+       if (inode->i_size < pb.last_block * fs->blocksize) {
+               printf ("Inode %ld, incorrect size, %ld (counted = %d). ",
+                       ino, inode->i_size,
+                       (pb.last_block+1) * fs->blocksize);
+               if (ask ("Set size to counted", 1)) {
+                       inode->i_size = (pb.last_block+1) * fs->blocksize;
+                       ext2fs_write_inode(fs, ino, inode);
+               } else
+                       ext2fs_unmark_valid(fs);
+       }
+       if (pb.num_blocks != inode->i_blocks) {
+               printf ("Inode %ld, i_blocks wrong %ld (counted=%d) .",
+                       ino, inode->i_blocks, pb.num_blocks);
+               if (ask ("Set i_blocks to counted", 1)) {
+                       inode->i_blocks = pb.num_blocks;
+                       ext2fs_write_inode(fs, ino, inode);
+               } else
+                               ext2fs_unmark_valid(fs);
+       }
+}      
+
+/*
+ * This is a helper function for check_blocks().
+ */
+int process_block(ext2_filsys fs,
+                 blk_t *block_nr,
+                 int blockcnt,
+                 void *private)
+{
+       struct process_block_struct *p;
+       int     group;
+       int     illegal_block = 0;
+       char    problem[80];
+       blk_t   firstblock;
+       blk_t   blk = *block_nr;
+
+       if (!blk)
+               return 0;
+       p = (struct process_block_struct *) private;
+
+#if 0
+       printf("Process_block, inode %d, block %d, #%d\n", p->ino, blk,
+              blockcnt);
+#endif 
+       
+       p->num_blocks++;
+       if (blockcnt > 0)
+               p->last_block = blockcnt;
+
+       firstblock = fs->super->s_first_data_block;
+       group = (blk - firstblock) / fs->super->s_blocks_per_group;
+       if (blk < firstblock) {
+               sprintf(problem, "< FIRSTBLOCK (%ld)", firstblock);
+               illegal_block++;
+       } else if (blk >= fs->super->s_blocks_count) {
+               sprintf(problem, "> BLOCKS (%ld)", fs->super->s_blocks_count);
+               illegal_block++;
+       } else if (blk == fs->group_desc[group].bg_block_bitmap) {
+               sprintf(problem, "is the block bitmap of group %d", group);
+               illegal_block++;
+       } else if (blk == fs->group_desc[group].bg_inode_bitmap) {
+               sprintf(problem, "is the inode bitmap of group %d", group);
+               illegal_block++;
+       } else if (blk >= fs->group_desc[group].bg_inode_table &&
+                  blk < fs->group_desc[group].bg_inode_table + fs->inode_blocks_per_group) {
+               sprintf(problem, "is in the inode table of group %d", group);
+               illegal_block++;
+       }
+       if (illegal_block) {
+               if (preen) {
+                       printf("Block %ld of inode %ld %s\n", blk, p->ino,
+                              problem);
+                       preenhalt();
+               }
+               if (p->fix == -1) {
+                       printf("Remove illegal block(s) in inode %ld", p->ino);
+                       p->fix = ask("", 1);
+               }
+               printf("Block #%d (%ld) %s.  %s\n", blockcnt, blk, problem,
+                      clear_msg[p->fix]);
+               if (p->fix) {
+                       *block_nr = 0;
+                       return BLOCK_CHANGED;
+               } else {
+                       ext2fs_unmark_valid(fs);
+                       return 0;
+               }
+       }
+
+       mark_block_used(fs, blk);
+       
+       if (p->is_dir && (blockcnt >= 0)) {
+               if (dir_block_count >= dir_block_size) {
+                       dir_block_size += 100;
+                       dir_blocks = realloc(dir_blocks,
+                                            dir_block_size *
+                                            sizeof(struct dir_block_struct));
+               }
+
+               dir_blocks[dir_block_count].blk = blk;
+               dir_blocks[dir_block_count].ino = p->ino;
+               dir_blocks[dir_block_count].blockcnt = blockcnt;
+               dir_block_count++;
+       }
+       
+#if 0
+       printf("process block, inode %d, block #%d is %d\n",
+              p->ino, blockcnt, blk);
+#endif
+       
+       return 0;
+}
+
+int process_bad_block(ext2_filsys fs,
+                     blk_t *block_nr,
+                     int blockcnt,
+                     void *private)
+{
+       struct process_block_struct *p;
+       errcode_t       retval;
+       blk_t           blk = *block_nr;
+       
+       if (!blk)
+               return 0;
+       p = (struct process_block_struct *) private;
+
+       if ((blk < fs->super->s_first_data_block) ||
+           (blk >= fs->super->s_blocks_count)) {
+               if (preen) {
+                       printf("Illegal block %ld in bad block inode\n", blk);
+                       preenhalt();
+               }
+               if (p->fix == -1)
+                       p->fix = ask("Remove illegal block(s) in bad block inode", 1);
+               printf("Illegal block %ld in bad block inode.  %s\n", blk,
+                      clear_msg[p->fix]);
+               if (p->fix) {
+                       *block_nr = 0;
+                       return BLOCK_CHANGED;
+               } else {
+                       ext2fs_unmark_valid(fs);
+                       return 0;
+               }
+       }
+
+       if (blockcnt < 0) {
+               mark_block_used(fs, blk);
+               return 0;
+       }
+#if 0 
+       printf ("DEBUG: Marking %d as bad.\n", blk);
+#endif
+       fs_badblocks_count++;
+       /*
+        * If the block is not used, then mark it as used and return.
+        * If it is already marked as found, this must mean that
+        * there's an overlap between the filesystem table blocks
+        * (bitmaps and inode table) and the bad block list.
+        */
+       if (!ext2fs_test_block_bitmap(fs, block_found_map, blk)) {
+               ext2fs_mark_block_bitmap(fs, block_found_map, blk);
+               return 0;
+       }
+       if (!bad_fs_block_map) {
+               retval = ext2fs_allocate_inode_bitmap(fs, &bad_fs_block_map);
+               if (retval) {
+                       com_err("ext2fs_allocate_block_bitmap", retval,
+                               "while allocating bad_fs_block_map");
+               fatal_error(0);
+               }
+       }
+       ext2fs_mark_block_bitmap(fs, bad_fs_block_map, blk);
+       return 0;
+}
+
+/*
+ * This routine gets called at the end of pass 1 if bad blocks are
+ * detected in the superblock, group descriptors, inode_bitmaps, or
+ * block bitmaps.  At this point, all of the blocks have been mapped
+ * out, so we can try to allocate new block(s) to replace the bad
+ * blocks.
+ */
+static void handle_fs_bad_blocks(ext2_filsys fs, char *block_buf)
+{
+       errcode_t       retval;
+       
+       printf("Warning: Bad block(s) found in filesystem-reserved blocks.\n");
+       
+       retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, block_buf,
+                                     process_fs_bad_block, 0);
+}
+
+static void new_table_block(ext2_filsys fs, blk_t first_block,
+                           const char *name, int num, blk_t *new_block)
+{
+       errcode_t       retval;
+       blk_t           old_block = *new_block;
+       int             i;
+       char            *buf;
+       
+       retval = ext2fs_get_free_blocks(fs, first_block,
+                       first_block + fs->super->s_blocks_per_group,
+                                       num, block_found_map, new_block);
+       if (retval) {
+               printf("Could not allocate %d block(s) for %s: %s\n",
+                      num, name, error_message(retval));
+               ext2fs_unmark_valid(fs);
+               return;
+       }
+       buf = malloc(fs->blocksize);
+       if (!buf) {
+               printf("Could not allocate block buffer for relocating %s\n",
+                      name);
+               ext2fs_unmark_valid(fs);
+               return;
+       }
+       ext2fs_mark_super_dirty(fs);
+       for (i = 0; i < num; i++) {
+               ext2fs_mark_block_bitmap(fs, block_found_map, (*new_block)+i);
+               retval = io_channel_read_blk(fs->io, old_block + i,
+                                            1, buf);
+               if (retval)
+                       printf("Warning: could not read block %ld of %s: %s\n",
+                              old_block + i, name, error_message(retval));
+               retval = io_channel_write_blk(fs->io, (*new_block) + i,
+                                             1, buf);
+               if (retval)
+                       printf("Warning: could not write block %ld for %s: %s\n",
+                              (*new_block) + i, name, error_message(retval));
+               /*
+                * If this particular block is not marked as bad, then
+                * clear its bit in the block_found map.  Otherwise,
+                * leave it set, since it is included in the bad
+                * blocks inode.
+                */
+               if (!ext2fs_test_block_bitmap(fs, bad_fs_block_map,
+                                             old_block + i))
+                       ext2fs_unmark_block_bitmap(fs, block_found_map,
+                                                  old_block + i);
+               /*
+                * Clear the bitmap since this block has now been moved.
+                */
+               ext2fs_unmark_block_bitmap(fs, bad_fs_block_map,
+                                          old_block + i);
+       }
+       free(buf);
+}
+
+/*
+ * Helper function for handle_fs_bad_blocks()
+ */
+static int process_fs_bad_block(ext2_filsys fs, blk_t *block_nr,
+                            int blockcnt, void *private)
+{
+       int     i;
+       blk_t   block = *block_nr;
+       int     first_block = fs->super->s_first_data_block;
+
+       /*
+        * If this block isn't one that is marked as a bad block in
+        * the filesystem tables, return
+        */
+       if (!ext2fs_test_block_bitmap(fs, bad_fs_block_map, block))
+               return 0;
+
+       for (i = 0; i < fs->group_desc_count; i++) {
+               if (block == first_block)
+                       printf("Bad block %ld in group %d's superblock.\n",
+                              block, i);
+               if (block == fs->group_desc[i].bg_block_bitmap) {
+                       printf("Bad block %ld in group %d's block bitmap.  ",
+                              block, i);
+                       if (ask("Relocate", 1)) {
+                               new_table_block(fs, first_block,
+                                               "block bitmap", 1, 
+                                       &fs->group_desc[i].bg_block_bitmap);
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+               if (block == fs->group_desc[i].bg_inode_bitmap) {
+                       printf("Bad block %ld in group %d's inode bitmap.  ",
+                              block, i);
+                       if (ask("Relocate", 1)) {
+                               new_table_block(fs, first_block,
+                                               "inode bitmap", 1, 
+                                       &fs->group_desc[i].bg_inode_bitmap);
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+               if ((block >= fs->group_desc[i].bg_inode_table) &&
+                   (block < (fs->group_desc[i].bg_inode_table +
+                             fs->inode_blocks_per_group))) {
+                       printf("WARNING: Severe data loss possible!!!!\n");
+                       printf("Bad block %ld in group %d's inode table.  ",
+                              block, i);
+                       if (ask("Relocate", 1)) {
+                               new_table_block(fs, first_block,
+                                               "inode table",
+                                               fs->inode_blocks_per_group, 
+                                       &fs->group_desc[i].bg_inode_table);
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+               if ((block > first_block) &&
+                   (block <= first_block + fs->desc_blocks))
+                       printf("Bad block %ld in group %d's copy of the descriptors.\n",
+                              block, i);
+               first_block += fs->super->s_blocks_per_group;
+       }
+       return 0;
+}
+
+/*
+ * This routine marks all blocks which are used by the superblock,
+ * group descriptors, inode bitmaps, and block bitmaps.
+ */
+static void mark_table_blocks(ext2_filsys fs)
+{
+       blk_t   block;
+       int     i,j;
+       
+       block = fs->super->s_first_data_block;
+       for (i = 0; i < fs->group_desc_count; i++) {
+               /*
+                * Mark block used for the block bitmap 
+                */
+               ext2fs_mark_block_bitmap(fs, block_found_map,
+                                        fs->group_desc[i].bg_block_bitmap);
+               /*
+                * Mark block used for the inode bitmap 
+                */
+               ext2fs_mark_block_bitmap(fs, block_found_map,
+                                        fs->group_desc[i].bg_inode_bitmap);
+               /*
+                * Mark the blocks used for the inode table
+                */
+               for (j = 0; j < fs->inode_blocks_per_group; j++)
+                       ext2fs_mark_block_bitmap(fs, block_found_map,
+                                                fs->group_desc[i].bg_inode_table + j);
+               /*
+                * Mark this group's copy of the superblock
+                */
+               ext2fs_mark_block_bitmap(fs, block_found_map, block);
+               
+               /*
+                * Mark this group's copy of the descriptors
+                */
+               for (j = 0; j < fs->desc_blocks; j++)
+                       ext2fs_mark_block_bitmap(fs, block_found_map,
+                                                block + j + 1);
+               block += fs->super->s_blocks_per_group;
+       }
+}
+       
+/*
+ * This 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 errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
+{
+       int     i;
+       
+       if (ino == stashed_ino) {
+               for (i=0; i < EXT2_N_BLOCKS; i++)
+                       blocks[i] = stashed_inode->i_block[i];
+               return 0;
+       }
+       printf("INTERNAL ERROR: pass1_get_blocks: unexpected inode #%ld\n",
+              ino);
+       printf("\t(was expecting %ld)\n", stashed_ino);
+       exit(FSCK_ERROR);
+}
+
+static errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino)
+{
+       if (ino == stashed_ino) {
+               if (!S_ISDIR(stashed_inode->i_mode))
+                       return ENOTDIR;
+               return 0;
+       }
+       printf("INTERNAL ERROR: pass1_check_directory: unexpected inode #%ld\n",
+              ino);
+       printf("\t(was expecting %ld)\n", stashed_ino);
+       exit(FSCK_ERROR);
+}
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
new file mode 100644 (file)
index 0000000..dd657bf
--- /dev/null
@@ -0,0 +1,640 @@
+/*
+ * pass1b.c --- Pass #1b of e2fsck
+ *
+ * This file contains pass1B, pass1C, and pass1D of e2fsck.  They are
+ * only invoked if pass 1 discovered blocks which are in use by more
+ * than one inode.
+ * 
+ * Pass1B scans the data blocks of all the inodes again, generating a
+ * complete list of duplicate blocks and which inodes have claimed
+ * them.
+ *
+ * Pass1C does a tree-traversal of the filesystem, to determine the
+ * parent directories of these inodes.  This step is necessary so that
+ * e2fsck can print out the pathnames of affected inodes.
+ *
+ * Pass1D is a reconciliation pass.  For each inode with duplicate
+ * blocks, the user is prompted if s/he would like to clone the file
+ * (so that the file gets a fresh copy of the duplicated blocks) or
+ * simply to delete the file.
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ * 
+ */
+
+#include <time.h>
+
+#include <et/com_err.h>
+#include "e2fsck.h"
+
+/*
+ * This is structure is allocated for each time that a block is
+ * claimed by more than one file.  So if a particular block is claimed
+ * by 3 files, then three copies of this structure will be allocated,
+ * one for each conflict.
+ *
+ * The linked list structure is as follows:
+ *
+ * dup_blk -->  block #34  --> block #35  --> block #47
+ *             inode #12      inode #14      inode #17
+ *             num_bad = 3    num_bad = 2    num_bad = 2
+ *               |              |               |
+ *               V              V               V
+ *             block #34      block #35      block #47
+ *             inode #14      inode #15      inode #23
+ *               |
+ *               V
+ *             block #34
+ *             inode #15
+ *
+ * The num_bad field indicates how many inodes are sharing a
+ * particular block, and is only stored in the first element of the
+ * linked list for a particular block.  As the block conflicts are
+ * resolved, num_bad is decremented; when it reaches 1, then we no
+ * longer need to worry about that block.
+ */
+struct dup_block {
+       blk_t           block;          /* Block number */
+       ino_t           ino;            /* Inode number */
+       int             num_bad;
+       /* Pointer to next dup record with different block */
+       struct dup_block *next_block;
+       /* Pointer to next dup record with different inode */
+       struct dup_block *next_inode;
+};
+
+/*
+ * This structure stores information about a particular inode which
+ * is sharing blocks with other inodes.  This information is collected
+ * to display to the user, so that the user knows what files he or she
+ * is dealing with, when trying to decide how to resolve the conflict
+ * of multiply-claimed blocks.
+ */
+struct dup_inode {
+       ino_t           ino;
+       time_t          mtime;
+       char            *pathname;
+       int             num_dupblocks;
+       int             flags;
+       struct dup_inode        *next;
+};
+
+#define DUP_INODE_DONT_FREE_PATHNAME   0x1
+
+static int process_pass1b_block(ext2_filsys fs, blk_t  *blocknr,
+                               int     blockcnt, void  *private);
+static void delete_file(ext2_filsys fs, struct dup_inode *dp,
+                       char *block_buf);
+static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf);
+static void pass1b(ext2_filsys fs, char *block_buf);
+static void pass1c(ext2_filsys fs, char *block_buf);
+static void pass1d(ext2_filsys fs, char *block_buf);
+
+static struct dup_block *dup_blk = 0;
+static struct dup_inode *dup_ino = 0;
+static int dup_inode_count = 0;
+
+/*
+ * For pass1_check_directory and pass1_get_blocks
+ */
+extern ino_t stashed_ino;
+extern struct ext2_inode *stashed_inode;
+
+static char *inode_dup_map;
+
+/*
+ * Main procedure for handling duplicate blocks
+ */
+void pass1_dupblocks(ext2_filsys fs, char *block_buf)
+{
+       errcode_t               retval;
+       struct dup_block        *p, *q, *next_p, *next_q;
+       struct dup_inode        *r, *next_r;
+       
+       retval = ext2fs_allocate_inode_bitmap(fs, &inode_dup_map);
+       if (retval) {
+               com_err("ext2fs_allocate_inode_bitmap", retval,
+                       "while allocating inode_dup_map");
+               fatal_error(0);
+       }
+       
+       pass1b(fs, block_buf);
+       pass1c(fs, block_buf);
+       pass1d(fs, block_buf);
+
+       /*
+        * Time to free all of the accumulated data structures that we
+        * don't need anymore.
+        */
+       free(inode_dup_map);    inode_dup_map = 0;
+       free(block_dup_map);    block_dup_map = 0;
+       for (p = dup_blk; p; p = next_p) {
+               next_p = p->next_block;
+               for (q = p; q; q = next_q) {
+                       next_q = q->next_inode;
+                       free(q);
+               }
+       }
+       for (r = dup_ino; r; r = next_r) {
+               next_r = r->next;
+               if (r->pathname && !(r->flags & DUP_INODE_DONT_FREE_PATHNAME))
+                       free(r->pathname);
+               free(r);
+       }
+}
+
+/*
+ * Scan the inodes looking for inodes that contain duplicate blocks.
+ */
+struct process_block_struct {
+       ino_t   ino;
+       int     dup_blocks;
+};
+
+void pass1b(ext2_filsys fs, char *block_buf)
+{
+       ino_t   ino;
+       struct ext2_inode inode;
+       ext2_inode_scan scan;
+       errcode_t       retval;
+       struct process_block_struct pb;
+       struct dup_inode *dp;
+       
+       printf("Duplicate blocks found... invoking duplicate block passes.\n");
+       printf("Pass 1B: Rescan for duplicate/bad blocks\n");
+       retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan);
+       if (retval) {
+               com_err(program_name, retval, "while opening inode scan");
+               fatal_error(0);
+       }
+       retval = ext2fs_get_next_inode(scan, &ino, &inode);
+       if (retval) {
+               com_err(program_name, retval, "while starting inode scan");
+               fatal_error(0);
+       }
+       stashed_inode = &inode;
+       while (ino) {
+               stashed_ino = ino;
+               if ((ino != EXT2_BAD_INO) &&
+                   (!ext2fs_test_inode_bitmap(fs, inode_used_map, ino) ||
+                    !inode_has_valid_blocks(&inode)))
+                       goto next;
+
+               pb.ino = ino;
+               pb.dup_blocks = 0;
+               retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
+                                             process_pass1b_block, &pb);
+               if (pb.dup_blocks) {
+                       if (ino != EXT2_BAD_INO)
+                               printf("\n");
+                       dp = allocate_memory(sizeof(struct dup_inode),
+                                            "duplicate inode record");
+                       dp->ino = ino;
+                       dp->mtime = inode.i_mtime;
+                       dp->num_dupblocks = pb.dup_blocks;
+                       dp->pathname = 0;
+                       dp->flags = 0;
+                       dp->next = dup_ino;
+                       dup_ino = dp;
+                       if (ino != EXT2_BAD_INO)
+                               dup_inode_count++;
+               }
+               if (retval)
+                       com_err(program_name, retval,
+                               "while calling ext2fs_block_iterate in pass1b");
+               
+       next:
+               retval = ext2fs_get_next_inode(scan, &ino, &inode);
+               if (retval) {
+                       com_err(program_name, retval,
+                               "while doing inode scan");
+                       fatal_error(0);
+               }
+       }
+       ext2fs_close_inode_scan(scan);
+       fs->get_blocks = 0;
+       fs->check_directory = 0;
+}
+
+int process_pass1b_block(ext2_filsys fs,
+                        blk_t  *block_nr,
+                        int blockcnt,
+                        void *private)
+{
+       struct process_block_struct *p;
+       struct dup_block *dp, *q, *r;
+       int i;
+
+       if (!*block_nr)
+               return 0;
+       p = (struct process_block_struct *) private;
+       
+       if (ext2fs_test_block_bitmap(fs, block_dup_map, *block_nr)) {
+               /* OK, this is a duplicate block */
+               if (p->ino != EXT2_BAD_INO) {
+                       if (!p->dup_blocks)
+                               printf("Duplicate/bad block(s) in inode %ld:",
+                                      p->ino);
+                       printf(" %ld", *block_nr);
+               }
+               p->dup_blocks++;
+               ext2fs_mark_block_bitmap(fs, block_dup_map, *block_nr);
+               ext2fs_mark_inode_bitmap(fs, inode_dup_map, p->ino);
+               dp = allocate_memory(sizeof(struct dup_block),
+                                     "duplicate block record");
+               dp->block = *block_nr;
+               dp->ino = p->ino;
+               dp->num_bad = 0;
+               q = dup_blk;
+               while (q) {
+                       if (q->block == *block_nr)
+                               break;
+                       q = q->next_block;
+               }
+               if (q) {
+                       dp->next_inode = q->next_inode;
+                       q->next_inode = dp;
+               } else {
+                       dp->next_block = dup_blk;
+                       dup_blk = dp;
+               }
+       }
+       /*
+        * Set the num_bad field
+        */
+       for (q = dup_blk; q; q = q->next_block) {
+               i = 0;
+               for (r = q; r; r = r->next_inode)
+                       i++;
+               q->num_bad = i;
+       }
+       return 0;
+}
+
+/*
+ * Used by pass1c to name the "special" inodes.  They are declared as
+ * writeable strings to prevent const problems.
+ */
+#define num_special_inodes     7
+char special_inode_name[num_special_inodes][40] =
+{
+       "<The NULL inode>",                     /* 0 */
+       "<The bad blocks inode>",               /* 1 */
+       "/",                                    /* 2 */
+       "<The ACL index inode>",                /* 3 */
+       "<The ACL data inode>",                 /* 4 */
+       "<The boot loader inode>",              /* 5 */
+       "<The undelete directory inode>"        /* 6 */
+};
+
+/*
+ * Pass 1c: Scan directories for inodes with duplicate blocks.  This
+ * is used so that we can print pathnames when prompting the user for
+ * what to do.
+ */
+struct process_dir_struct {
+       ext2_filsys     fs;
+       ino_t           dir_ino;
+       int             count;
+};
+
+void pass1c(ext2_filsys fs, char *block_buf)
+{
+       int     i;
+       struct dup_inode        *p;
+       errcode_t       retval;
+       char    buf[80];
+       int     inodes_left = dup_inode_count;
+       int     offset, entry;
+       struct ext2_dir_entry *dirent;
+
+       printf("Pass 1C: Scan directories for inodes with dup blocks.\n");
+
+       /*
+        * First check to see if any of the inodes with dup blocks is
+        * the bad block inode or the root inode; handle them as
+        * special cases.
+        */
+       for (p = dup_ino; p; p = p->next) {
+               if (p->ino < num_special_inodes) {
+                       p->pathname = special_inode_name[p->ino];
+                       p->flags |= DUP_INODE_DONT_FREE_PATHNAME;
+                       inodes_left--;
+               }
+       }
+
+       /*
+        * Search through all directories to translate inodes to names
+        * (by searching for the containing directory for that inode.)
+        */
+       for (i=0; inodes_left && i < dir_block_count; i++) {
+               retval = io_channel_read_blk(fs->io, dir_blocks[i].blk,
+                                            1, block_buf);
+               entry = offset = 0;
+               while (offset < fs->blocksize) {
+                       entry++;
+                       dirent = (struct ext2_dir_entry *)
+                               (block_buf + offset);
+                       if (!dirent->inode ||
+                           ((dir_blocks[i].blockcnt == 0) && (entry <= 2)))
+                               goto next;
+
+                       if (!ext2fs_test_inode_bitmap(fs, inode_dup_map,
+                                                     dirent->inode))
+                               goto next;
+
+                       for (p = dup_ino; p; p = p->next) {
+                               if (p->ino == dirent->inode)
+                                       break;
+                       }
+
+                       if (!p || p->pathname)
+                               goto next;
+                       
+                       (void) ext2fs_get_pathname(fs, dir_blocks[i].ino,
+                                                  p->ino, &p->pathname);
+                       inodes_left--;
+                       
+               next:
+                       if (dirent->rec_len < 8)
+                               break;
+                       offset += dirent->rec_len;
+               }
+       }
+
+
+       /*
+        * If we can't get a name, then put in a generic one.
+        */
+       for (p = dup_ino; p; p = p->next) {
+               if (!p->pathname) {
+                       sprintf(buf, "<Unknown inode #%ld>", p->ino);
+                       p->pathname = malloc(strlen(buf)+1);
+                       if (!p->pathname) {
+                               fprintf(stderr, "pass1c: couldn't malloc "
+                                       "generic pathname\n");
+                               fatal_error(0);
+                       }
+                       strcpy(p->pathname, buf);
+               }
+       }
+}      
+
+static void pass1d(ext2_filsys fs, char *block_buf)
+{
+       struct dup_inode        *p, *s;
+       struct dup_block        *q, *r;
+       ino_t   *shared;
+       int     shared_len;
+       int     i;
+       errcode_t       retval;
+       char    *time_str;
+       int     file_ok;
+       
+       printf("Pass 1D: Reconciling duplicate blocks\n");
+       read_bitmaps(fs);
+
+       printf("(There are %d inodes containing duplicate/bad blocks.)\n\n",
+              dup_inode_count);
+       shared = allocate_memory(sizeof(ino_t) * dup_inode_count,
+                                "Shared inode list");
+       for (p = dup_ino; p; p = p->next) {
+               shared_len = 0;
+               file_ok = 1;
+               if (p->ino == EXT2_BAD_INO)
+                       continue;
+
+               /*
+                * Search through the duplicate records to see which
+                * inodes share blocks with this one
+                */
+               for (q = dup_blk; q; q = q->next_block) {
+                       /*
+                        * See if this block is used by this inode.
+                        * If it isn't, continue.
+                        */
+                       for (r = q; r; r = r->next_inode)
+                               if (r->ino == p->ino)
+                                       break;
+                       if (!r)
+                               continue;
+                       if (q->num_bad > 1)
+                               file_ok = 0;
+                       /*
+                        * Add all inodes used by this block to the
+                        * shared[] --- which is a unique list, so
+                        * if an inode is already in shared[], don't
+                        * add it again.
+                        */
+                       for (r = q; r; r = r->next_inode) {
+                               if (r->ino == p->ino)
+                                       continue;
+                               for (i = 0; i < shared_len; i++)
+                                       if (shared[i] == r->ino)
+                                               break;
+                               if (i == shared_len) {
+                                       shared[shared_len++] = r->ino;
+                               }
+                       }
+               }
+               time_str = ctime(&p->mtime);
+               time_str[24] = 0;
+               printf("File %s (inode #%ld, mod time %s) \n",
+                      p->pathname, p->ino, time_str);
+               printf("  has %d duplicate blocks, shared with %d file%s:\n",
+                      p->num_dupblocks, shared_len,
+                      (shared_len>1) ? "s" : "");
+               for (i = 0; i < shared_len; i++) {
+                       for (s = dup_ino; s; s = s->next)
+                               if (s->ino == shared[i])
+                                       break;
+                       if (!s)
+                               continue;
+                       time_str = ctime(&s->mtime);
+                       time_str[24] = 0;
+                       printf("\t%s (inode #%ld, mod time %s)\n",
+                              s->pathname, s->ino, time_str);
+               }
+               if (file_ok) {
+                       printf("Duplicated blocks already reassigned or cloned.\n\n");
+                       continue;
+               }
+                       
+               if (ask("Clone duplicate/bad blocks", 1)) {
+                       retval = clone_file(fs, p, block_buf);
+                       if (retval)
+                               printf("Couldn't clone file: %s\n",
+                                      error_message(retval));
+                       else {
+                               printf("\n");
+                               continue;
+                       }
+               }
+               if (ask("Delete file", 1))
+                       delete_file(fs, p, block_buf);
+               else
+                       ext2fs_unmark_valid(fs);
+               printf("\n");
+       }
+}
+
+static int delete_file_block(ext2_filsys fs,
+                            blk_t      *block_nr,
+                            int blockcnt,
+                            void *private)
+{
+       struct dup_block *p;
+
+       if (!*block_nr)
+               return 0;
+
+       if (ext2fs_test_block_bitmap(fs, block_dup_map, *block_nr)) {
+               for (p = dup_blk; p; p = p->next_block)
+                       if (p->block == *block_nr)
+                               break;
+               if (p) {
+                       p->num_bad--;
+                       if (p->num_bad == 1)
+                               ext2fs_unmark_block_bitmap(fs, block_dup_map,
+                                                          *block_nr);
+               } else
+                       com_err("delete_file_block", 0,
+                               "internal error; can't find dup_blk for %d\n",
+                               *block_nr);
+       } else {
+               ext2fs_unmark_block_bitmap(fs, block_found_map, *block_nr);
+               ext2fs_unmark_block_bitmap(fs, fs->block_map, *block_nr);
+       }
+               
+       return 0;
+}
+               
+static void delete_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
+{
+       errcode_t       retval;
+       struct process_block_struct pb;
+       struct ext2_inode       inode;
+
+       pb.ino = dp->ino;
+       pb.dup_blocks = dp->num_dupblocks;
+       
+       retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf,
+                                     delete_file_block, &pb);
+       if (retval)
+               com_err("delete_file", retval,
+                       "while calling ext2fs_block_iterate for inode %d",
+                       dp->ino);
+       ext2fs_unmark_inode_bitmap(fs, inode_used_map, dp->ino);
+       ext2fs_unmark_inode_bitmap(fs, inode_dir_map, dp->ino);
+       if (inode_bad_map)
+               ext2fs_unmark_inode_bitmap(fs, inode_bad_map, dp->ino);
+       ext2fs_unmark_inode_bitmap(fs, fs->inode_map, dp->ino);
+       ext2fs_mark_ib_dirty(fs);
+       ext2fs_mark_bb_dirty(fs);
+       retval = ext2fs_read_inode(fs, dp->ino, &inode);
+       if (retval) {
+               com_err("delete_file", retval, "while reading inode %d",
+                       dp->ino);
+               return;
+       }
+       inode.i_links_count = 0;
+       inode.i_dtime = time(0);
+       retval = ext2fs_write_inode(fs, dp->ino, &inode);
+       if (retval) {
+               com_err("delete_file", retval, "while writing inode %d",
+                       dp->ino);
+               return;
+       }
+}
+
+struct clone_struct {
+       errcode_t       errcode;
+       char    *buf;
+};
+
+static int clone_file_block(ext2_filsys fs,
+                           blk_t       *block_nr,
+                           int blockcnt,
+                           void *private)
+{
+       struct dup_block *p;
+       blk_t   new_block;
+       errcode_t       retval;
+       struct clone_struct *cs = (struct clone_struct *) private;
+
+       if (!*block_nr)
+               return 0;
+
+       if (ext2fs_test_block_bitmap(fs, block_dup_map, *block_nr)) {
+               for (p = dup_blk; p; p = p->next_block)
+                       if (p->block == *block_nr)
+                               break;
+               if (p) {
+                       retval = ext2fs_new_block(fs, 0, block_found_map,
+                                                 &new_block);
+                       if (retval) {
+                               cs->errcode = retval;
+                               return BLOCK_ABORT;
+                       }
+                       retval = io_channel_read_blk(fs->io, *block_nr, 1,
+                                                    cs->buf);
+                       if (retval) {
+                               cs->errcode = retval;
+                               return BLOCK_ABORT;
+                       }
+                       retval = io_channel_write_blk(fs->io, new_block, 1,
+                                                     cs->buf);
+                       if (retval) {
+                               cs->errcode = retval;
+                               return BLOCK_ABORT;
+                       }
+                       p->num_bad--;
+                       if (p->num_bad == 1)
+                               ext2fs_unmark_block_bitmap(fs, block_dup_map,
+                                                          *block_nr);
+                       *block_nr = new_block;
+                       ext2fs_mark_block_bitmap(fs, block_found_map,
+                                                new_block);
+                       ext2fs_mark_block_bitmap(fs, fs->block_map, new_block);
+                       return BLOCK_CHANGED;
+               } else
+                       com_err("clone_file_block", 0,
+                               "internal error; can't find dup_blk for %d\n",
+                               *block_nr);
+       }
+       return 0;
+}
+               
+static int clone_file(ext2_filsys fs, struct dup_inode *dp, char* block_buf)
+{
+       errcode_t       retval;
+       struct clone_struct cs;
+
+       cs.errcode = 0;
+       cs.buf = malloc(fs->blocksize);
+       if (!cs.buf)
+               return ENOMEM;
+       
+       retval = ext2fs_block_iterate(fs, dp->ino, 0, block_buf,
+                                     clone_file_block, &cs);
+       ext2fs_mark_bb_dirty(fs);
+       free(cs.buf);
+       if (retval) {
+               com_err("clone_file", retval,
+                       "while calling ext2fs_block_iterate for inode %d",
+                       dp->ino);
+               return retval;
+       }
+       if (cs.errcode) {
+               com_err("clone_file", retval,
+                       "returned from clone_file_block");
+               return retval;
+       }
+       return 0;
+}
+
+
+       
+
+       
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
new file mode 100644 (file)
index 0000000..327cf16
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * pass2.c --- check directory structure
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ * 
+ * Pass 2 of e2fsck iterates through all active directory inodes, and
+ * applies to following tests to each directory entry in the directory
+ * blocks in the inodes:
+ *
+ *     - The length of the directory entry (rec_len) should be at
+ *             least 8 bytes, and no more than the remaining space
+ *             left in the directory block.
+ *     - The length of the name in the directory entry (name_len)
+ *             should be less than (rec_len - 8).  
+ *     - The inode number in the directory entry should be within
+ *             legal bounds.
+ *     - The inode number should refer to a in-use inode.
+ *     - The first entry should be '.', and its inode should be
+ *             the inode of the directory.
+ *     - The second entry should be '..'.
+ *
+ * To minimize disk seek time, the directory blocks are processed in
+ * sorted order of block numbers.
+ *
+ * Pass 2 also collects the following information:
+ *     - The inode numbers of the subdirectories for each directory.
+ *
+ * Pass 2 relies on the following information from previous passes:
+ *     - The directory information collected in pass 1.
+ *     - The inode_used_map bitmap
+ *     - The inode_bad_map bitmap
+ *     - The inode_dir_map bitmap
+ *     - The block_dup_map bitmap
+ *
+ * Pass 2 frees the following data structures
+ *     - The inode_bad_map bitmap
+ */
+
+#include "et/com_err.h"
+
+#include "e2fsck.h"
+
+/*
+ * Keeps track of how many times an inode is referenced.
+ */
+unsigned short * inode_count;
+
+static void deallocate_inode(ext2_filsys fs, ino_t ino,
+                            char* block_buf);
+static int process_bad_inode(ext2_filsys fs, ino_t dir, ino_t ino);
+static int check_dir_block(ext2_filsys fs,
+                          struct dir_block_struct *dir_blocks_info,
+                          char *buf);
+
+void pass2(ext2_filsys fs)
+{
+       int     i;
+       char    *buf;
+       struct resource_track   rtrack;
+       
+       init_resource_track(&rtrack);
+
+#ifdef MTRACE
+       mtrace_print("Pass 2");
+#endif
+
+       if (!preen)
+               printf("Pass 2: Checking directory structure\n");
+       inode_count = allocate_memory((fs->super->s_inodes_count + 1) *
+                                     sizeof(unsigned short),
+                                     "buffer for inode count");
+
+       buf = allocate_memory(fs->blocksize, "directory scan buffer");
+
+       for (i=0; i < dir_block_count; i++)
+               check_dir_block(fs, &dir_blocks[i], buf);
+            
+       free(buf);
+       free(dir_blocks);
+       if (inode_bad_map) {
+               free(inode_bad_map);
+               inode_bad_map = 0;
+       }
+       if (tflag > 1) {
+               printf("Pass 2: ");
+               print_resource_track(&rtrack);
+       }
+}
+
+/*
+ * Make sure the first entry in the directory is '.', and that the
+ * directory entry is sane.
+ */
+static int check_dot(ext2_filsys fs,
+                    struct ext2_dir_entry *dirent,
+                    ino_t ino)
+{
+       struct ext2_dir_entry *nextdir;
+       int     status = 0;
+       int     created = 0;
+       int     new_len;
+       char    name[BLOCK_SIZE];
+       
+       if (!dirent->inode) {
+               printf("Missing '.' in directory inode %ld.\n", ino);
+               if (dirent->rec_len < 12)
+                       fatal_error("Cannot fix, insufficient space to add '.'");
+               preenhalt();
+               if (ask("Fix", 1)) {
+                       dirent->inode = ino;
+                       dirent->name_len = 1;
+                       dirent->name[0] = '.';
+                       status = 1;
+                       created = 1;
+               } else {
+                       ext2fs_unmark_valid(fs);
+                       return 0;
+               }
+       }
+       if ((dirent->name_len != 1) ||
+           strncmp(dirent->name, ".", dirent->name_len)) {
+               strncpy(name, dirent->name, dirent->name_len);
+               name[dirent->name_len] = '\0';
+               printf("Missing '.' in directory inode %ld.\n", ino);
+               printf("Cannot fix, first entry in directory contains '%s'\n",
+                      name);
+               exit(FSCK_ERROR);
+       }
+       if (dirent->inode != ino) {
+               printf("Bad inode number for '.' in directory inode %ld.\n",
+                      ino);
+               preenhalt();
+               if (ask("Fix", 1)) {
+                       dirent->inode = ino;
+                       status = 1;
+               } else
+                       ext2fs_unmark_valid(fs);
+       }
+       if (dirent->rec_len > 12) {
+               new_len = dirent->rec_len - 12;
+               if (new_len > 12) {
+                       preenhalt();
+                       if (created ||
+                           ask("Directory entry for '.' is big.  Split", 1)) {
+                               nextdir = (struct ext2_dir_entry *)
+                                       ((char *) dirent + 12);
+                               dirent->rec_len = 12;
+                               nextdir->rec_len = new_len;
+                               nextdir->inode = 0;
+                               nextdir->name_len = 0;
+                               status = 1;
+                       }
+               }
+       }
+       return status;
+}
+
+/*
+ * Make sure the second entry in the directory is '..', and that the
+ * directory entry is sane.  We do not check the inode number of '..'
+ * here; this gets done in pass 3.
+ */
+static int check_dotdot(ext2_filsys fs,
+                       struct ext2_dir_entry *dirent,
+                       struct dir_info *dir)
+{
+       char    name[BLOCK_SIZE];
+       int     ino = dir->ino;
+       
+       if (!dirent->inode) {
+               printf("Missing '..' in directory inode %d.\n", ino);
+               if (dirent->rec_len < 12)
+                       fatal_error("Cannot fix, insufficient space to add '..'");
+               preenhalt();
+               if (ask("Fix", 1)) {
+                       /*
+                        * Note: we don't have the parent inode just
+                        * yet, so we will fill it in with the root
+                        * inode.  This will get fixed in pass 3.
+                        */
+                       dirent->inode = EXT2_ROOT_INO;
+                       dirent->name_len = 2;
+                       dirent->name[0] = '.';
+                       dirent->name[1] = '.';
+                       return 1;
+               } else
+                       ext2fs_unmark_valid(fs);
+               return 0;
+       }
+       if ((dirent->name_len != 2) ||
+           strncmp(dirent->name, "..", dirent->name_len)) {
+               strncpy(name, dirent->name, dirent->name_len);
+               name[dirent->name_len] = '\0';
+               printf("Missing '..' in directory inode %d.\n", ino);
+               printf("Cannot fix, first entry in directory contains %s\n",
+                      name);
+               exit(FSCK_ERROR);
+       }
+       dir->dotdot = dirent->inode;
+       return 0;
+}
+
+/*
+ * Check to make sure a directory entry doesn't contain any illegal
+ * characters.
+ */
+static int check_name(ext2_filsys fs,
+                     struct ext2_dir_entry *dirent,
+                     ino_t dir_ino,
+                     char *name)
+{
+       int     i;
+       int     fixup = -1;
+       char    *pathname;
+       int     ret = 0;
+       errcode_t       retval;
+       
+       for ( i = 0; i < dirent->name_len; i++) {
+               if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
+                       if (fixup < 0) {
+                               retval = ext2fs_get_pathname(fs, dir_ino,
+                                                            0, &pathname);
+                               if (retval) {
+                                       com_err(program_name, retval, "while getting pathname in check_name");
+                                       fatal_error(0);
+                               }
+                               printf ("Bad file name '%s' (contains '/' or "
+                                       " null) in directory '%s'",
+                                       pathname, name);
+                               free(pathname);
+                               preenhalt();
+                               fixup = ask("Replace '/' or null by '.'", 1);
+                       }
+                       if (fixup) {
+                               dirent->name[i] = '.';
+                               ret = 1;
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+       }
+       return ret;
+}
+
+static int check_dir_block(ext2_filsys fs,
+                          struct dir_block_struct *db,
+                          char *buf)
+{
+       struct dir_info         *subdir, *dir;
+       struct ext2_dir_entry   *dirent;
+       char                    name[BLOCK_SIZE];
+       int                     offset = 0;
+       int                     dir_modified = 0;
+       errcode_t               retval;
+       char                    *path1, *path2;
+       int                     dot_state;
+       blk_t                   block_nr = db->blk;
+       ino_t                   ino = db->ino;
+       static char             unknown[] = "???";
+
+       /*
+        * Make sure the inode is still in use (could have been 
+        * deleted in the duplicate/bad blocks pass.
+        */
+       if (!(ext2fs_test_inode_bitmap(fs, inode_used_map, ino))) 
+               return 0;
+       
+       if (db->blockcnt)
+               dot_state = 2;
+       else
+               dot_state = 0;
+
+#if 0
+       printf("In process_dir_block block %d, #%d, inode %d\n", block_nr,
+              db->blockcnt, ino);
+#endif
+       
+       retval = io_channel_read_blk(fs->io, block_nr, 1, buf);
+       if (retval) {
+               com_err(program_name, retval,
+                       "while reading directory block %d", block_nr);
+       }
+
+       do {
+               dot_state++;
+               dirent = (struct ext2_dir_entry *) (buf + offset);
+               if (((offset + dirent->rec_len) > fs->blocksize) ||
+                   (dirent->rec_len < 8) ||
+                   ((dirent->name_len+8) > dirent->rec_len)) {
+                       printf("Directory inode %ld, block %d, offset %d: directory corrupted\n",
+                              ino, db->blockcnt, offset);
+                       preenhalt();
+                       if (ask("Salvage", 1)) {
+                               dirent->rec_len = fs->blocksize - offset;
+                               dirent->name_len = 0;
+                               dirent->inode = 0;
+                               dir_modified++;
+                       } else {
+                               ext2fs_unmark_valid(fs);
+                               return DIRENT_ABORT;
+                       }
+               }
+               strncpy(name, dirent->name, dirent->name_len);
+               name[dirent->name_len] = '\0';
+               if (dot_state == 1) {
+                       if (check_dot(fs, dirent, ino))
+                               dir_modified++;
+               } else if (dot_state == 2) {
+                       dir = get_dir_info(ino);
+                       if (!dir) {
+                               printf("Internal error: couldn't find dir_info for %ld\n",
+                                      ino);
+                               fatal_error(0);
+                       }
+                       if (check_dotdot(fs, dirent, dir))
+                               dir_modified++;
+               } else if (dirent->inode == ino) {
+                       retval = ext2fs_get_pathname(fs, ino, 0, &path1);
+                       if (retval)
+                               path1 = unknown;
+                       printf("Entry '%s' in %s (%ld) is a link to '.'  ",
+                              name, path1, ino);
+                       if (path1 != unknown)
+                               free(path1);
+                       preenhalt();
+                       if (ask("Clear", 1)) {
+                               dirent->inode = 0;
+                               dir_modified++;
+                       }
+               }
+               if (!dirent->inode) 
+                       goto next;
+               
+#if 0
+               printf("Entry '%s', name_len %d, rec_len %d, inode %d... ",
+                      name, dirent->name_len, dirent->rec_len, dirent->inode);
+#endif
+               if (check_name(fs, dirent, ino, name))
+                       dir_modified++;
+
+               /*
+                * Make sure the inode listed is a legal one.
+                */ 
+               if (((dirent->inode != EXT2_ROOT_INO) &&
+                    (dirent->inode < EXT2_FIRST_INO)) ||
+                   (dirent->inode > fs->super->s_inodes_count)) {
+                       retval = ext2fs_get_pathname(fs, ino, 0, &path1);
+                       if (retval)
+                               path1 = unknown;
+                       printf("Entry '%s' in %s (%ld) has bad inode #: %ld.\n",
+                              name, path1, ino, dirent->inode);
+                       if (path1 != unknown)
+                               free(path1);
+                       preenhalt();
+                       if (ask("Clear", 1)) {
+                               dirent->inode = 0;
+                               dir_modified++;
+                               goto next;
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+
+               /*
+                * If the inode is unusued, offer to clear it.
+                */
+               if (!(ext2fs_test_inode_bitmap(fs, inode_used_map,
+                                              dirent->inode))) {
+                       retval = ext2fs_get_pathname(fs, ino, 0, &path1);
+                       if (retval)
+                               path1 = unknown;
+                       printf("Entry '%s' in %s (%ld) has deleted/unused inode %ld.\n",
+                              name, path1, ino, dirent->inode);
+                       if (path1 != unknown)
+                               free(path1);
+                       if (ask("Clear", 1)) {
+                               dirent->inode = 0;
+                               dir_modified++;
+                               goto next;
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+
+               /*
+                * If the inode was marked as having bad fields in
+                * pass1, process it and offer to fix/clear it.
+                * (We wait until now so that we can display the
+                * pathname to the user.)
+                */
+               if (inode_bad_map &&
+                   ext2fs_test_inode_bitmap(fs, inode_bad_map,
+                                            dirent->inode)) {
+                       if (process_bad_inode(fs, ino, dirent->inode)) {
+                               dirent->inode = 0;
+                               dir_modified++;
+                               goto next;
+                       }
+               }
+
+               /*
+                * If this is a directory, then mark its parent in its
+                * dir_info structure.  If the parent field is already
+                * filled in, then this directory has more than one
+                * hard link.  We assume the first link is correct,
+                * and ask the user if he/she wants to clear this one.
+                */
+               if ((dot_state > 2) &&
+                   (ext2fs_test_inode_bitmap(fs, inode_dir_map,
+                                             dirent->inode))) {
+                       subdir = get_dir_info(dirent->inode);
+                       if (!subdir) {
+                               printf("INTERNAL ERROR: missing dir %ld\n",
+                                      dirent->inode);
+                               fatal_error(0);
+                       }
+                       if (subdir->parent) {
+                               retval = ext2fs_get_pathname(fs, ino,
+                                                            0, &path1);
+                               if (retval)
+                                       path1 = unknown;
+                               retval = ext2fs_get_pathname(fs,
+                                                            subdir->parent,
+                                                            dirent->inode,
+                                                            &path2);
+                               if (retval)
+                                       path2 = unknown;
+                               printf("Entry '%s' in %s (%ld) is a link to directory %s (%ld).\n",
+                                      name, path1, ino, path2, 
+                                      dirent->inode);
+                               if (path1 != unknown)
+                                       free(path1);
+                               if (path2 != unknown)
+                                       free(path2);
+                               if (ask("Clear", 1)) {
+                                       dirent->inode = 0;
+                                       dir_modified++;
+                                       goto next;
+                               } else
+                                       ext2fs_unmark_valid(fs);
+                       }
+                       subdir->parent = ino;
+               }
+               
+               if (inode_count[dirent->inode]++ > 0)
+                       fs_links_count++;
+               fs_total_count++;
+       next:
+               offset += dirent->rec_len;
+       } while (offset < fs->blocksize);
+#if 0
+       printf("\n");
+#endif
+       if (offset != fs->blocksize) {
+               printf("Final rec_len is %d, should be %d\n",
+                      dirent->rec_len,
+                      dirent->rec_len - fs->blocksize + offset);
+       }
+       if (dir_modified) {
+               retval = io_channel_write_blk(fs->io, block_nr,
+                                             1, buf);
+               if (retval) {
+                       com_err(program_name, retval,
+                               "while writing directory block %d", block_nr);
+               }
+               ext2fs_mark_changed(fs);
+       }
+       return 0;
+}
+
+/*
+ * This function is called to deallocate a block, and is an interator
+ * functioned called by deallocate inode via ext2fs_iterate_block().
+ */
+static int deallocate_inode_block(ext2_filsys fs,
+                            blk_t      *block_nr,
+                            int blockcnt,
+                            void *private)
+{
+       if (!*block_nr)
+               return 0;
+       ext2fs_unmark_block_bitmap(fs, block_found_map, *block_nr);
+       ext2fs_unmark_block_bitmap(fs, fs->block_map, *block_nr);
+       return 0;
+}
+               
+/*
+ * This fuction deallocates an inode
+ */
+static void deallocate_inode(ext2_filsys fs, ino_t ino,
+                            char* block_buf)
+{
+       errcode_t               retval;
+       struct ext2_inode       inode;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval) {
+               com_err("deallocate_inode", retval, "while reading inode %d",
+                       ino);
+               return;
+       }
+       inode.i_links_count = 0;
+       inode.i_dtime = time(0);
+       retval = ext2fs_write_inode(fs, ino, &inode);
+       if (retval) {
+               com_err("deallocate_inode", retval, "while writing inode %d",
+                       ino);
+               return;
+       }
+       /*
+        * Fix up the bitmaps...
+        */
+       read_bitmaps(fs);
+       ext2fs_unmark_inode_bitmap(fs, inode_used_map, ino);
+       ext2fs_unmark_inode_bitmap(fs, inode_dir_map, ino);
+       if (inode_bad_map)
+               ext2fs_unmark_inode_bitmap(fs, inode_bad_map, ino);
+       ext2fs_unmark_inode_bitmap(fs, fs->inode_map, ino);
+       ext2fs_mark_ib_dirty(fs);
+
+       if (!inode_has_valid_blocks(&inode))
+               return;
+       
+       ext2fs_mark_bb_dirty(fs);
+       retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
+                                     deallocate_inode_block, 0);
+       if (retval)
+               com_err("deallocate_inode", retval,
+                       "while calling ext2fs_block_iterate for inode %d",
+                       ino);
+}
+
+/*
+ * These two subroutines are used by process_bad_inode; it is used to
+ * make sure that certain reserved fields are really zero.  If not,
+ * prompt the user if he/she wants us to zeroize them.
+ */
+static void check_for_zero_long(ext2_filsys fs, ino_t ino, char *pathname,
+                               const char *name, unsigned long *val,
+                               int *modified)
+{
+       char prompt[80];
+       
+       if (*val) {
+               printf("%s for inode %ld (%s) is %ld, should be zero.\n",
+                      name, ino, pathname, *val);
+               preenhalt();
+               sprintf(prompt, "Clear %s", name);
+               if (ask(prompt, 1)) {
+                       *val = 0;
+                       *modified = 1;
+               } else
+                       ext2fs_unmark_valid(fs);
+       }
+}
+
+static void check_for_zero_char(ext2_filsys fs, ino_t ino, char *pathname,
+                               const char *name, unsigned char *val,
+                               int *modified)
+{
+       char prompt[80];
+       
+       if (*val) {
+               printf("%s for inode %ld (%s) is %d, should be zero.\n",
+                      name, ino, pathname, *val);
+               preenhalt();
+               sprintf(prompt, "Clear %s", name);
+               if (ask(prompt, 1)) {
+                       *val = 0;
+                       *modified = 1;
+               } else
+                       ext2fs_unmark_valid(fs);
+       }
+}
+
+       
+
+static int process_bad_inode(ext2_filsys fs, ino_t dir, ino_t ino)
+{
+       struct ext2_inode       inode;
+       errcode_t               retval;
+       int                     inode_modified = 0;
+       char                    *pathname;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval) {
+               com_err("process_bad_inode", retval, "while reading inode %d",
+                       ino);
+               return 0;
+       }       
+       retval = ext2fs_get_pathname(fs, dir, ino, &pathname);
+       if (retval) {
+               com_err("process_bad_inode", retval,
+                       "while getting pathname for inode %d",
+                       ino);
+               return 0;
+       }
+       if (!S_ISDIR(inode.i_mode) && !S_ISREG(inode.i_mode) &&
+           !S_ISCHR(inode.i_mode) && !S_ISBLK(inode.i_mode) &&
+           !S_ISLNK(inode.i_mode) && !S_ISFIFO(inode.i_mode) &&
+           !(S_ISSOCK(inode.i_mode))) {
+               printf("Inode %ld (%s) has a bad mode (0%o).\n",
+                      ino, pathname, inode.i_mode);
+               preenhalt();
+               if (ask("Clear", 1)) {
+                       deallocate_inode(fs, ino, 0);
+                       return 1;
+               } else
+                       ext2fs_unmark_valid(fs);
+       }
+       check_for_zero_long(fs, ino, pathname, "i_faddr", &inode.i_faddr,
+                           &inode_modified);
+       check_for_zero_char(fs, ino, pathname, "i_frag", &inode.i_frag,
+                           &inode_modified);
+       check_for_zero_char(fs, ino, pathname, "i_fsize", &inode.i_fsize,
+                           &inode_modified);
+       check_for_zero_long(fs, ino, pathname, "i_file_acl", &inode.i_file_acl,
+                           &inode_modified);
+       check_for_zero_long(fs, ino, pathname, "i_dir_acl", &inode.i_dir_acl,
+                           &inode_modified);
+       free(pathname);
+       if (inode_modified) {
+               retval = ext2fs_write_inode(fs, ino, &inode);
+               if (retval) {
+                       com_err("process_bad_inode", retval,
+                               "while writing inode %d",
+                               ino);
+                       return 0;
+               }
+       }
+       return 0;
+}
+
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
new file mode 100644 (file)
index 0000000..b34acd2
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * pass3.c -- pass #3 of e2fsck: Check for directory connectivity
+ *
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ * 
+ * Pass #3 assures that all directories are connected to the
+ * filesystem tree, using the following algorithm:
+ *
+ * First, the root directory is checked to make sure it exists; if
+ * not, e2fsck will offer to create a new one.  It is then marked as
+ * "done".
+ * 
+ * Then, pass3 interates over all directory inodes; for each directory
+ * it attempts to trace up the filesystem tree, using dirinfo.parent
+ * until it reaches a directory which has been marked "done".  If it
+ * can not do so, then the directory must be disconnected, and e2fsck
+ * will offer to reconnect it to /lost+found.  While it is chasing
+ * parent pointers up the filesystem tree, if pass3 sees a directory
+ * twice, then it has detected a filesystem loop, and it will again
+ * offer to reconnect the directory to /lost+found in to break the
+ * filesystem loop.
+ * 
+ * Pass 3 also contains the subroutine, reconnect_file() to reconnect
+ * inodes to /lost+found; this subroutine is also used by pass 4.
+ * reconnect_file() calls get_lost_and_found(), which is responsible
+ * for creating /lost+found if it does not exist.
+ *
+ * Pass 3 frees the following data structures:
+ *             - The dirinfo directory information cache.
+ */
+
+#include "et/com_err.h"
+
+#include "e2fsck.h"
+
+static void check_root(ext2_filsys fs, ino_t root_ino);
+static void check_directory(ext2_filsys fs, ino_t dir);
+static ino_t get_lost_and_found(ext2_filsys fs);
+static void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent);
+static int adjust_inode_count(ext2_filsys fs, ino_t ino, int adj);
+static errcode_t expand_directory(ext2_filsys fs, ino_t dir);
+
+static ino_t lost_and_found = 0;
+static int bad_lost_and_found = 0;
+
+static char *inode_loop_detect;
+static char *inode_done_map;
+       
+void pass3(ext2_filsys fs)
+{
+       int             i;
+       errcode_t       retval;
+       struct resource_track   rtrack;
+       
+       init_resource_track(&rtrack);
+
+#ifdef MTRACE
+       mtrace_print("Pass 3");
+#endif
+
+       if (!preen)
+               printf("Pass 3: Checking directory connectivity\n");
+
+       /*
+        * Allocate some bitmaps to do loop detection.
+        */
+       retval = ext2fs_allocate_inode_bitmap(fs, &inode_loop_detect);
+       if (retval) {
+               com_err("ext2fs_allocate_inode_bitmap", retval,
+                       "while allocating inode_loop_detect");
+               fatal_error(0);
+       }
+       retval = ext2fs_allocate_inode_bitmap(fs, &inode_done_map);
+       if (retval) {
+               com_err("ext2fs_allocate_inode_bitmap", retval,
+                       "while allocating inode_done_map");
+               fatal_error(0);
+       }
+       if (tflag) {
+               printf("Peak memory: ");
+               print_resource_track(&global_rtrack);
+       }
+
+       check_root(fs, EXT2_ROOT_INO);
+       ext2fs_mark_inode_bitmap(fs, inode_done_map, EXT2_ROOT_INO);
+
+       for (i=1; i <= fs->super->s_inodes_count; i++) {
+               if (ext2fs_test_inode_bitmap(fs, inode_dir_map, i))
+                       check_directory(fs, i);
+       }
+       
+       free_dir_info(fs);
+       free(inode_loop_detect);
+       free(inode_done_map);
+       if (tflag > 1) {
+               printf("Pass 3: ");
+               print_resource_track(&rtrack);
+       }
+}
+
+/*
+ * This makes sure the root inode is present; if not, we ask if the
+ * user wants us to create it.  Not creating it is a fatal error.
+ */
+void check_root(ext2_filsys fs, ino_t root_ino)
+{
+       blk_t                   blk;
+       errcode_t               retval;
+       struct ext2_inode       inode;
+       char *                  block;
+       struct dir_info         *dir;
+       
+       if (ext2fs_test_inode_bitmap(fs, inode_used_map, root_ino)) {
+               /*
+                * If the root inode is a directory, die here.  The
+                * user must have answered 'no' in pass1 when we
+                * offered to clear it.
+                */
+               if (!(ext2fs_test_inode_bitmap(fs, inode_dir_map, root_ino)))
+                       fatal_error("Root inode not directory");
+               
+               /*
+                * Set up the parent pointer for the root; this isn't
+                * done anywhere else, so we do it here.
+                */
+               dir = get_dir_info(root_ino);
+               dir->parent = root_ino;
+               
+               return;
+       }
+
+       printf("Root inode not allocated.  ");
+       preenhalt();
+       if (!ask("Rellocate", 1)) {
+               ext2fs_unmark_valid(fs);
+               fatal_error("Cannot proceed without a root inode.");
+       }
+
+       read_bitmaps(fs);
+       
+       /*
+        * First, find a free block
+        */
+       retval = ext2fs_new_block(fs, 0, block_found_map, &blk);
+       if (retval) {
+               com_err("ext2fs_new_block", retval,
+                       "while trying to create root directory");
+               fatal_error(0);
+       }
+       ext2fs_mark_block_bitmap(fs, block_found_map, blk);
+       ext2fs_mark_block_bitmap(fs, fs->block_map, blk);
+       ext2fs_mark_bb_dirty(fs);
+
+       /*
+        * Now let's create the actual data block for the inode
+        */
+       retval = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
+                                     &block);
+       if (retval) {
+               com_err("ext2fs_new_dir_block", retval,
+                       "while creating new root directory");
+               fatal_error(0);
+       }
+
+       retval = io_channel_write_blk(fs->io, blk, 1, block);
+       if (retval) {
+               com_err("io_channel_write_blk", retval,
+                       "while writing the root directory block");
+               fatal_error(0);
+       }
+       free(block);
+
+       /*
+        * Set up the inode structure
+        */
+       memset(&inode, 0, sizeof(inode));
+       inode.i_mode = 040755;
+       inode.i_size = fs->blocksize;
+       inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
+       inode.i_links_count = 2;
+       inode.i_blocks = fs->blocksize / 512;
+       inode.i_block[0] = blk;
+
+       /*
+        * Write out the inode.
+        */
+       retval = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode);
+       if (retval) {
+               com_err("ext2fs_write_inode", retval,
+                       "While trying to create /lost+found");
+               fatal_error(0);
+       }
+       
+       /*
+        * Miscellaneous bookkeeping...
+        */
+       add_dir_info(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, &inode);
+       inode_count[EXT2_ROOT_INO] = 2;
+       inode_link_info[EXT2_ROOT_INO] = 2;
+
+       ext2fs_mark_inode_bitmap(fs, inode_used_map, EXT2_ROOT_INO);
+       ext2fs_mark_inode_bitmap(fs, inode_dir_map, EXT2_ROOT_INO);
+       ext2fs_mark_inode_bitmap(fs, fs->inode_map, EXT2_ROOT_INO);
+       ext2fs_mark_ib_dirty(fs);
+}
+
+/*
+ * This subroutine is responsible for making sure that a particular
+ * directory is connected to the root; if it isn't we trace it up as
+ * far as we can go, and then offer to connect the resulting parent to
+ * the lost+found.  We have to do loop detection; if we ever discover
+ * a loop, we treat that as a disconnected directory and offer to
+ * reparent it to lost+found.
+ */
+static void check_directory(ext2_filsys fs, ino_t ino)
+{
+       struct dir_info *dir;
+       struct dir_info *p;
+       errcode_t       retval;
+       char            *path1, *path2, *path3;
+       static char unknown[] = "???";
+
+       dir = get_dir_info(ino);
+       if (!dir) {
+               printf("Internal error: couldn't find dir_info for %ld\n",
+                      ino);
+               fatal_error(0);
+       }
+
+       memset(inode_loop_detect, 0, (fs->super->s_inodes_count / 8) + 1);
+       p = dir;
+       while (p) {
+               /*
+                * If we find a parent which we've already checked,
+                * then stop; we know it's either already connected to
+                * the directory tree, or it isn't but the user has
+                * already told us he doesn't want us to reconnect the
+                * disconnected subtree.
+                */
+               if (ext2fs_test_inode_bitmap(fs, inode_done_map, p->ino))
+                       goto check_dot_dot;
+               /*
+                * Mark this inode as being "done"; by the time we
+                * return from this function, the inode we either be
+                * verified as being connected to the directory tree,
+                * or we will have offered to reconnect this to
+                * lost+found.
+                */
+               ext2fs_mark_inode_bitmap(fs, inode_done_map, p->ino);
+               /*
+                * If this directory doesn't have a parent, or we've
+                * seen the parent once already, then offer to
+                * reparent it to lost+found
+                */
+               if (!p->parent ||
+                   (ext2fs_test_inode_bitmap(fs, inode_loop_detect,
+                                             p->parent)))
+                       break;
+               ext2fs_mark_inode_bitmap(fs, inode_loop_detect,
+                                        p->parent);
+               p = get_dir_info(p->parent);
+       }
+       /*
+        * If we've reached here, we've hit a detached directory
+        * inode; offer to reconnect it to lost+found.
+        */
+       retval = ext2fs_get_pathname(fs, p->ino, 0, &path1);
+       if (retval)
+               path1 = unknown;
+
+       printf("Unconnected directory inode %li (%s)\n", p->ino, path1);
+       if (path1 != unknown)
+               free(path1);
+       preenhalt();
+       if (ask("Connect to /lost+found", 1)) {
+               if (reconnect_file(fs, p->ino))
+                       ext2fs_unmark_valid(fs);
+               else {
+                       p->parent = lost_and_found;
+                       fix_dotdot(fs, p, lost_and_found);
+               }
+               
+       } else
+               ext2fs_unmark_valid(fs);
+
+       /*
+        * Make sure that .. and the parent directory are the same;
+        * offer to fix it if not.
+        */
+check_dot_dot:
+       if (dir->parent != dir->dotdot) {
+               retval = ext2fs_get_pathname(fs, dir->parent, ino,
+                                            &path1);
+               if (retval)
+                       path1 = unknown;
+               retval = ext2fs_get_pathname(fs, dir->dotdot, 0, &path2);
+               if (retval)
+                       path2 = unknown;
+               retval = ext2fs_get_pathname(fs, dir->parent, 0, &path3);
+               if (retval)
+                       path3 = unknown;
+               
+               printf("'..' in %s (%ld) is %s (%ld), should be %s (%ld).\n",
+                      path1, ino, path2, dir->dotdot,
+                      path3, dir->parent);
+               if (path1 != unknown)
+                       free(path1);
+               if (path2 != unknown)
+                       free(path2);
+               if (path3 != unknown)
+                       free(path3);
+               if (ask("Fix", 1))
+                       fix_dotdot(fs, dir, dir->parent);
+               else
+                       ext2fs_unmark_valid(fs);
+       }
+}      
+
+/*
+ * This routine gets the lost_and_found inode, making it a directory
+ * if necessary
+ */
+ino_t get_lost_and_found(ext2_filsys fs)
+{
+       ino_t                   ino;
+       blk_t                   blk;
+       errcode_t               retval;
+       struct ext2_inode       inode;
+       char *                  block;
+       const char *            name = "lost+found";
+
+       retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino);
+       if (!retval)
+               return ino;
+       if (retval != ENOENT)
+               printf("Error while trying to find /lost+found: %s",
+                      error_message(retval));
+       else
+               printf("/lost+found not found.  ");
+       preenhalt();
+       if (!ask("Create", 1)) {
+               ext2fs_unmark_valid(fs);
+               return 0;
+       }
+
+       /*
+        * Read the inode and block bitmaps in; we'll be messing with
+        * them.
+        */
+       read_bitmaps(fs);
+       
+       /*
+        * First, find a free block
+        */
+       retval = ext2fs_new_block(fs, 0, block_found_map, &blk);
+       if (retval) {
+               com_err("ext2fs_new_block", retval,
+                       "while trying to create /lost+found directory");
+               return 0;
+       }
+       ext2fs_mark_block_bitmap(fs, block_found_map, blk);
+       ext2fs_mark_block_bitmap(fs, fs->block_map, blk);
+       ext2fs_mark_bb_dirty(fs);
+
+       /*
+        * Next find a free inode.
+        */
+       retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040755, inode_used_map,
+                                 &ino);
+       if (retval) {
+               com_err("ext2fs_new_inode", retval,
+                       "while trying to create /lost+found directory");
+               return 0;
+       }
+       ext2fs_mark_inode_bitmap(fs, inode_used_map, ino);
+       ext2fs_mark_inode_bitmap(fs, inode_dir_map, ino);
+       ext2fs_mark_inode_bitmap(fs, fs->inode_map, ino);
+       ext2fs_mark_ib_dirty(fs);
+
+       /*
+        * Now let's create the actual data block for the inode
+        */
+       retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
+       if (retval) {
+               com_err("ext2fs_new_dir_block", retval,
+                       "while creating new directory block");
+               return 0;
+       }
+
+       retval = io_channel_write_blk(fs->io, blk, 1, block);
+       if (retval) {
+               com_err("io_channel_write_blk", retval,
+                       "while writing the directory block for /lost+found");
+               return 0;
+       }
+       free(block);
+
+       /*
+        * Set up the inode structure
+        */
+       memset(&inode, 0, sizeof(inode));
+       inode.i_mode = 040755;
+       inode.i_size = fs->blocksize;
+       inode.i_atime = inode.i_ctime = inode.i_mtime = time(0);
+       inode.i_links_count = 2;
+       inode.i_blocks = fs->blocksize / 512;
+       inode.i_block[0] = blk;
+
+       /*
+        * Next, write out the inode.
+        */
+       retval = ext2fs_write_inode(fs, ino, &inode);
+       if (retval) {
+               com_err("ext2fs_write_inode", retval,
+                       "While trying to create /lost+found");
+               return 0;
+       }
+       /*
+        * Finally, create the directory link
+        */
+       retval = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, 0);
+       if (retval) {
+               com_err("ext2fs_link", retval, "While creating /lost+found");
+               return 0;
+       }
+
+       /*
+        * Miscellaneous bookkeeping that needs to be kept straight.
+        */
+       add_dir_info(fs, ino, EXT2_ROOT_INO, &inode);
+       adjust_inode_count(fs, EXT2_ROOT_INO, +1);
+       inode_count[ino] = 2;
+       inode_link_info[ino] = 2;
+#if 0
+       printf("/lost+found created; inode #%d\n", ino);
+#endif
+       return ino;
+}
+
+/*
+ * This routine will connect a file to lost+found
+ */
+int reconnect_file(ext2_filsys fs, ino_t inode)
+{
+       errcode_t       retval;
+       char            name[80];
+       
+       if (bad_lost_and_found) {
+               printf("Bad or nonexistent /lost+found.  Cannot reconnect.\n");
+               return 1;
+       }
+       if (!lost_and_found) {
+               lost_and_found = get_lost_and_found(fs);
+               if (!lost_and_found) {
+                       printf("Bad or nonexistent /lost+found.  Cannot reconnect.\n");
+                       bad_lost_and_found++;
+                       return 1;
+               }
+       }
+
+       sprintf(name, "#%ld", inode);
+       retval = ext2fs_link(fs, lost_and_found, name, inode, 0);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               if (!ask("No room in /lost+found; expand /lost+found", 1))
+                       return 1;
+               retval = expand_directory(fs, lost_and_found);
+               if (retval) {
+                       printf("Could not expand /lost+found: %s\n",
+                              error_message(retval));
+                       return 1;
+               }
+               retval = ext2fs_link(fs, lost_and_found, name, inode, 0);
+       }
+       if (retval) {
+               printf("Could not reconnect %ld: %s\n", inode,
+                      error_message(retval));
+               return 1;
+       }
+
+       adjust_inode_count(fs, inode, +1);
+
+       return 0;
+}
+
+/*
+ * Utility routine to adjust the inode counts on an inode.
+ */
+static int adjust_inode_count(ext2_filsys fs, ino_t ino, int adj)
+{
+       errcode_t               retval;
+       struct ext2_inode       inode;
+       
+       if (!ino)
+               return 0;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval)
+               return retval;
+
+#if 0
+       printf("Adjusting link count for inode %d by %d (from %d)\n", ino, adj,
+              inode.i_links_count);
+#endif
+
+       inode.i_links_count += adj;
+       inode_count[ino] += adj;
+       inode_link_info[ino] += adj;
+
+       retval = ext2fs_write_inode(fs, ino, &inode);
+       if (retval)
+               return retval;
+
+       return 0;
+}
+
+/*
+ * Fix parent --- this routine fixes up the parent of a directory.
+ */
+struct fix_dotdot_struct {
+       ext2_filsys     fs;
+       ino_t           parent;
+       int             done;
+};
+
+static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
+                          int  offset,
+                          int  blocksize,
+                          char *buf,
+                          void *private)
+{
+       struct fix_dotdot_struct *fp = (struct fix_dotdot_struct *) private;
+       errcode_t       retval;
+
+       if (dirent->name_len != 2)
+               return 0;
+       if (strncmp(dirent->name, "..", 2))
+               return 0;
+       
+       retval = adjust_inode_count(fp->fs, dirent->inode, -1);
+       if (retval)
+               printf("Error while adjusting inode count on inode %ld\n",
+                      dirent->inode);
+       retval = adjust_inode_count(fp->fs, fp->parent, 1);
+       if (retval)
+               printf("Error while adjusting inode count on inode %ld\n",
+                      fp->parent);
+
+       dirent->inode = fp->parent;
+
+       fp->done++;
+       return DIRENT_ABORT | DIRENT_CHANGED;
+}
+
+static void fix_dotdot(ext2_filsys fs, struct dir_info *dir, ino_t parent)
+{
+       errcode_t       retval;
+       struct fix_dotdot_struct fp;
+
+       fp.fs = fs;
+       fp.parent = parent;
+       fp.done = 0;
+
+#if 0
+       printf("Fixing '..' of inode %d to be %d...\n", dir->ino, parent);
+#endif
+       
+       retval = ext2fs_dir_iterate(fs, dir->ino, DIRENT_FLAG_INCLUDE_EMPTY,
+                                   0, fix_dotdot_proc, &fp);
+       if (retval || !fp.done) {
+               printf("Couldn't fix parent of inode %ld: %s\n\n",
+                      dir->ino, retval ? error_message(retval) :
+                      "Couldn't find parent direntory entry");
+               ext2fs_unmark_valid(fs);
+       }
+       dir->dotdot = parent;
+       
+       return;
+}
+
+/*
+ * These routines are responsible for expanding a /lost+found if it is
+ * too small.
+ */
+
+struct expand_dir_struct {
+       int     done;
+       errcode_t       err;
+};
+
+static int expand_dir_proc(ext2_filsys fs,
+                          blk_t        *blocknr,
+                          int  blockcnt,
+                          void *private)
+{
+       struct expand_dir_struct *es = (struct expand_dir_struct *) private;
+       blk_t   new_blk;
+       static blk_t    last_blk = 0;
+       char            *block;
+       errcode_t       retval;
+       
+       if (*blocknr) {
+               last_blk = *blocknr;
+               return 0;
+       }
+       retval = ext2fs_new_block(fs, last_blk, block_found_map, &new_blk);
+       if (retval) {
+               es->err = retval;
+               return BLOCK_ABORT;
+       }
+       if (blockcnt > 0) {
+               retval = ext2fs_new_dir_block(fs, 0, 0, &block);
+               if (retval) {
+                       es->err = retval;
+                       return BLOCK_ABORT;
+               }
+               es->done = 1;
+       } else {
+               block = malloc(fs->blocksize);
+               if (!block) {
+                       es->err = ENOMEM;
+                       return BLOCK_ABORT;
+               }
+               memset(block, 0, fs->blocksize);
+       }       
+       retval = io_channel_write_blk(fs->io, new_blk, 1, block);
+       if (retval) {
+               es->err = retval;
+               return BLOCK_ABORT;
+       }
+       free(block);
+       *blocknr = new_blk;
+       ext2fs_mark_block_bitmap(fs, block_found_map, new_blk);
+       ext2fs_mark_block_bitmap(fs, fs->block_map, new_blk);
+       ext2fs_mark_bb_dirty(fs);
+       if (es->done)
+               return (BLOCK_CHANGED | BLOCK_ABORT);
+       else
+               return BLOCK_CHANGED;
+}
+
+static errcode_t expand_directory(ext2_filsys fs, ino_t dir)
+{
+       errcode_t       retval;
+       struct expand_dir_struct es;
+       struct ext2_inode       inode;
+       
+       if (!(fs->flags & EXT2_FLAG_RW))
+               return EXT2_ET_RO_FILSYS;
+
+       retval = ext2fs_check_directory(fs, dir);
+       if (retval)
+               return retval;
+       
+       es.done = 0;
+       es.err = 0;
+       
+       retval = ext2fs_block_iterate(fs, dir, BLOCK_FLAG_APPEND,
+                                     0, expand_dir_proc, &es);
+
+       if (es.err)
+               return es.err;
+       if (!es.done)
+               return EXT2_ET_EXPAND_DIR_ERR;
+
+       /*
+        * Update the size and block count fields in the inode.
+        */
+       retval = ext2fs_read_inode(fs, dir, &inode);
+       if (retval)
+               return retval;
+       
+       inode.i_size += fs->blocksize;
+       inode.i_blocks += fs->blocksize / 512;
+
+       retval = ext2fs_write_inode(fs, dir, &inode);
+       if (retval)
+               return retval;
+
+       return 0;
+}
+
+
+               
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
new file mode 100644 (file)
index 0000000..290e1b9
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * pass4.c -- pass #4 of e2fsck: Check reference counts
+ *
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ * 
+ */
+
+#include "e2fsck.h"
+
+void pass4(ext2_filsys fs)
+{
+       int     i;
+       struct ext2_inode       inode;
+       struct resource_track   rtrack;
+       
+       init_resource_track(&rtrack);
+
+#ifdef MTRACE
+       mtrace_print("Pass 4");
+#endif
+
+       if (!preen)
+               printf("Pass 4: Check reference counts.\n");
+       for (i=1; i <= fs->super->s_inodes_count; i++) {
+               if (i == EXT2_BAD_INO ||
+                   (i > EXT2_ROOT_INO && i < EXT2_FIRST_INO))
+                       continue;
+               if (!(ext2fs_test_inode_bitmap(fs, inode_used_map, i)))
+                       continue;
+               if (inode_count[i] == 0) {
+                       /*
+                        * Inode isn't attached to the filesystem;
+                        * prompt to reconnect.
+                        */
+                       printf("Unattached inode %d\n", i);
+                       preenhalt();
+                       if (ask("Connect to /lost+found", 1)) {
+                               if (reconnect_file(fs, i))
+                                       ext2fs_unmark_valid(fs);
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+               if (inode_count[i] != inode_link_info[i]) {
+                       ext2fs_read_inode(fs, i, &inode);
+                       if (inode_link_info[i] != inode.i_links_count) {
+                               printf("WARNING: PROGRAMMING BUG IN E2FSCK!\n");
+                               printf("inode_link_info[%d] is %d, "
+                                      "inode.i_links_count is %d.  "
+                                      "They should be the same!\n",
+                                      i, inode_link_info[i],
+                                      inode.i_links_count);
+                       }
+                       printf("Inode %d has ref count %d, expecting %d.\n",
+                              i, inode.i_links_count, inode_count[i]);
+                       if (ask("Set i_nlinks to count", 1)) {
+                               inode.i_links_count = inode_count[i];
+                               ext2fs_write_inode(fs, i, &inode);
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+       }
+       free(inode_link_info);  inode_link_info = 0;
+       free(inode_count);      inode_count = 0;
+       if (tflag > 1) {
+               printf("Pass 4: ");
+               print_resource_track(&rtrack);
+       }
+}
+
diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c
new file mode 100644 (file)
index 0000000..cd0cf5b
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * pass5.c --- check block and inode bitmaps against on-disk bitmaps
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ * 
+ */
+
+#include "et/com_err.h"
+
+#include "e2fsck.h"
+
+static void check_block_bitmaps(ext2_filsys fs);
+static void check_inode_bitmaps(ext2_filsys fs);
+static void check_inode_end(ext2_filsys fs);
+static void check_block_end(ext2_filsys fs);
+
+static int do_fix = -1;
+static const char *fix_question = "Fix summary information";
+
+void pass5(ext2_filsys fs)
+{
+       struct resource_track   rtrack;
+       
+#ifdef MTRACE
+       mtrace_print("Pass 5");
+#endif
+
+       init_resource_track(&rtrack);
+       
+       if (!preen)
+               printf("Pass 5: Checking group summary information.\n");
+
+       read_bitmaps(fs);
+
+       check_block_bitmaps(fs);
+       check_inode_bitmaps(fs);
+       check_inode_end(fs);
+       check_block_end(fs);
+
+       free(inode_used_map);
+       free(inode_dir_map);
+       free(block_found_map);
+
+       if (tflag > 1) {
+               printf("Pass 5: ");
+               print_resource_track(&rtrack);
+       }
+}
+
+static void check_block_bitmaps(ext2_filsys fs)
+{
+       int     i;
+       int     *free_array;
+       int     group = 0;
+       int     blocks = 0;
+       int     free_blocks = 0;
+       int     group_free = 0;
+       int     actual, bitmap;
+       const char      *print_header = "Block bitmap differences:";
+       
+       free_array = allocate_memory(fs->group_desc_count * sizeof(int),
+                                    "free block count array");
+                                    
+       for (i = fs->super->s_first_data_block;
+            i < fs->super->s_blocks_count;
+            i++) {
+               actual = ext2fs_test_block_bitmap(fs, block_found_map, i);
+               bitmap = ext2fs_test_block_bitmap(fs, fs->block_map, i);
+               
+               if (actual == bitmap)
+                       goto do_counts;
+
+               if (do_fix < 0)
+                       do_fix = ask(fix_question, 1);
+               if (print_header) {
+                       printf(print_header);
+                       print_header = 0;
+               }
+               if (!actual && bitmap) {
+                       /*
+                        * Block not used, but marked in use in the bitmap.
+                        */
+                       printf(" -%d", i);
+                       if (do_fix)
+                               ext2fs_unmark_block_bitmap(fs, fs->block_map,
+                                                          i);
+               } else {
+                       /*
+                        * Block used, but not marked in use in the bitmap.
+                        */
+                       printf(" +%d", i);
+                       if (do_fix)
+                               ext2fs_mark_block_bitmap(fs, fs->block_map,
+                                                        i);
+               }
+               if (do_fix) {
+                       ext2fs_mark_bb_dirty(fs);
+                       bitmap = actual;
+               } else
+                       ext2fs_unmark_valid(fs);
+                       
+       do_counts:
+               if (!bitmap) {
+                       group_free++;
+                       free_blocks++;
+               }
+               blocks ++;
+               if ((blocks == fs->super->s_blocks_per_group) ||
+                   (i == fs->super->s_blocks_count-1)) {
+                       free_array[group] = group_free;
+                       group ++;
+                       blocks = 0;
+                       group_free = 0;
+               }
+       }
+       if (!print_header)
+               printf(".  %s\n", fix_msg[do_fix]);
+       for (i = 0; i < fs->group_desc_count; i++) {
+               if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
+                       if (do_fix < 0)
+                               do_fix = ask(fix_question, 1);
+                       printf("Free blocks count wrong for group %d (%d, counted=%d).  %s\n",
+                              i, fs->group_desc[i].bg_free_blocks_count,
+                              free_array[i], fix_msg[do_fix]);
+                       if (do_fix) {
+                               fs->group_desc[i].bg_free_blocks_count =
+                                       free_array[i];
+                               ext2fs_mark_super_dirty(fs);
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+       }
+       if (free_blocks != fs->super->s_free_blocks_count) {
+               if (do_fix < 0)
+                       do_fix = ask(fix_question, 1);
+               printf("Free blocks count wrong (%ld, counted=%d).  %s\n",
+                      fs->super->s_free_blocks_count, free_blocks,
+                      fix_msg[do_fix]);
+               if (do_fix) {
+                       fs->super->s_free_blocks_count = free_blocks;
+                       ext2fs_mark_super_dirty(fs);
+               } else
+                       ext2fs_unmark_valid(fs);
+       }
+}
+                       
+static void check_inode_bitmaps(ext2_filsys fs)
+{
+       int     i;
+       int     free_inodes = 0;
+       int     group_free = 0;
+       int     dirs_count = 0;
+       int     group = 0;
+       int     inodes = 0;
+       int     *free_array;
+       int     *dir_array;
+       int     actual, bitmap;
+       const char *print_header = "Inode bitmap differences:";
+       
+       free_array = allocate_memory(fs->group_desc_count * sizeof(int),
+                                    "free inode count array");
+                                    
+       dir_array = allocate_memory(fs->group_desc_count * sizeof(int),
+                                   "directory count array");
+                                    
+       for (i = 1; i <= fs->super->s_inodes_count; i++) {
+               actual = ext2fs_test_inode_bitmap(fs, inode_used_map, i);
+               bitmap = ext2fs_test_inode_bitmap(fs, fs->inode_map, i);
+               
+               if (actual == bitmap)
+                       goto do_counts;
+               
+               if (do_fix < 0)
+                       do_fix = ask(fix_question, 1);
+               if (print_header) {
+                       printf(print_header);
+                       print_header = 0;
+               }
+               if (!actual && bitmap) {
+                       /*
+                        * Inode wasn't used, but marked in bitmap
+                        */
+                       printf(" -%d", i);
+                       if (do_fix)
+                               ext2fs_unmark_inode_bitmap(fs, fs->inode_map,
+                                                          i);
+               } else if (actual && !bitmap) {
+                       /*
+                        * Inode used, but not in bitmap
+                        */
+                       printf (" +%d", i);
+                       if (do_fix)
+                               ext2fs_mark_inode_bitmap(fs, fs->inode_map, i);
+               }
+               if (do_fix) {
+                       ext2fs_mark_ib_dirty(fs);
+                       bitmap = actual;
+               } else
+                       ext2fs_unmark_valid(fs);
+                       
+do_counts:
+               if (!bitmap) {
+                       group_free++;
+                       free_inodes++;
+               } else {
+                       if (ext2fs_test_inode_bitmap(fs, inode_dir_map, i))
+                               dirs_count++;
+               }
+               inodes++;
+               if ((inodes == fs->super->s_inodes_per_group) ||
+                   (i == fs->super->s_inodes_count)) {
+                       free_array[group] = group_free;
+                       dir_array[group] = dirs_count;
+                       group ++;
+                       inodes = 0;
+                       group_free = 0;
+                       dirs_count = 0;
+               }
+       }
+       if (!print_header)
+               printf(".  %s\n", fix_msg[do_fix]);
+       
+       for (i = 0; i < fs->group_desc_count; i++) {
+               if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
+                       if (do_fix < 0)
+                               do_fix = ask(fix_question, 1);
+                       printf ("Free inodes count wrong for group #%d (%d, counted=%d).  %s\n",
+                               i, fs->group_desc[i].bg_free_inodes_count,
+                               free_array[i], fix_msg[do_fix]);
+                       if (do_fix) {
+                               fs->group_desc[i].bg_free_inodes_count =
+                                       free_array[i];
+                               ext2fs_mark_super_dirty(fs);
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+               if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
+                       if (do_fix < 0)
+                               do_fix = ask(fix_question, 1);
+                       printf ("Directories count wrong for group #%d (%d, counted=%d).  %s\n",
+                               i, fs->group_desc[i].bg_used_dirs_count,
+                               dir_array[i], fix_msg[do_fix]);
+                       if (do_fix) {
+                               fs->group_desc[i].bg_used_dirs_count =
+                                       dir_array[i];
+                               ext2fs_mark_super_dirty(fs);
+                       } else
+                               ext2fs_unmark_valid(fs);
+               }
+       }
+       if (free_inodes != fs->super->s_free_inodes_count) {
+               if (do_fix < 0)
+                       do_fix = ask(fix_question, 1);
+               printf("Free inodes count wrong (%ld, counted=%d).  %s\n",
+                      fs->super->s_free_inodes_count, free_inodes,
+                      fix_msg[do_fix]);
+               if (do_fix) {
+                       fs->super->s_free_inodes_count = free_inodes;
+                       ext2fs_mark_super_dirty(fs);
+               } else
+                       ext2fs_unmark_valid(fs);
+       }
+}
+
+static void check_inode_end(ext2_filsys fs)
+{
+       ino_t   end;
+       ino_t   save_inodes_count = fs->super->s_inodes_count;
+       ino_t   i;
+
+       end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
+       if (save_inodes_count == end)
+               return;
+       
+       fs->super->s_inodes_count = end;
+
+       for (i = save_inodes_count + 1; i <= end; i++) {
+               if (!ext2fs_test_inode_bitmap(fs, fs->inode_map, i)) {
+                       printf("Padding at end of inode bitmap is not set. ");
+                       if (ask("Fix", 1)) {
+                               for (i = save_inodes_count + 1; i <= end; i++)
+                                       ext2fs_mark_inode_bitmap(fs,
+                                                                fs->inode_map,
+                                                                i);
+                               ext2fs_mark_ib_dirty(fs);
+                       } else
+                               ext2fs_unmark_valid(fs);
+                       break;
+               }
+       }
+
+       fs->super->s_inodes_count = save_inodes_count;
+}
+
+static void check_block_end(ext2_filsys fs)
+{
+       blk_t   end;
+       blk_t   save_blocks_count = fs->super->s_blocks_count;
+       blk_t   i;
+
+       end = fs->super->s_first_data_block +
+               (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count);
+
+       if (save_blocks_count == end)
+               return;
+       
+       fs->super->s_blocks_count = end;
+
+       for (i = save_blocks_count; i < end; i++) {
+               if (!ext2fs_test_block_bitmap(fs, fs->block_map, i)) {
+                       printf("Padding at end of block bitmap is not set. ");
+
+                       if (ask("Fix", 1)) {
+                               for (i = save_blocks_count + 1; i < end; i++)
+                                       ext2fs_mark_block_bitmap(fs,
+                                                                fs->block_map,
+                                                                i);
+                               ext2fs_mark_bb_dirty(fs);
+                       } else
+                               ext2fs_unmark_valid(fs);
+                       break;
+               }
+       }
+
+       fs->super->s_blocks_count = save_blocks_count;
+}
+
diff --git a/e2fsck/util.c b/e2fsck/util.c
new file mode 100644 (file)
index 0000000..c9e6396
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * util.c --- miscellaneous utilities
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <termios.h>
+#include <sys/resource.h>
+
+#include "e2fsck.h"
+
+const char * fix_msg[2] = { "IGNORED", "FIXED" };
+const char * clear_msg[2] = { "IGNORED", "CLEARED" };
+
+void fatal_error (const char *msg)
+{
+       if (msg) 
+               fprintf (stderr, "%s: %s\n", program_name, msg);
+       exit(FSCK_ERROR);
+}
+
+void *allocate_memory(int size, const char *description)
+{
+       void *ret;
+       char buf[256];
+
+#ifdef DEBUG_ALLOCATE_MEMORY
+       printf("Allocating %d bytes for %s...\n", size, description);
+#endif
+       ret = malloc(size);
+       if (!ret) {
+               sprintf(buf, "%%s: Can't allocate %s\n", description);
+               fatal_error(buf);
+       }
+       memset(ret, 0, size);
+       return ret;
+}
+
+
+int ask_yn(const char * string, int def)
+{
+       int             c;
+       struct termios  termios, tmp;
+       const char      *defstr;
+
+       tcgetattr (0, &termios);
+       tmp = termios;
+       tmp.c_lflag &= ~(ICANON | ECHO);
+       tcsetattr (0, TCSANOW, &tmp);
+
+       if (def == 1)
+               defstr = "<y>";
+       else if (def == 0)
+               defstr = "<n>";
+       else
+               defstr = " (y/n)";
+       printf("%s%s? ", string, defstr);
+       while (1) {
+               fflush (stdout);
+               if ((c = getchar()) == EOF)
+                       break;
+               c = toupper(c);
+               if (c == 'Y') {
+                       def = 1;
+                       break;
+               }
+               else if (c == 'N') {
+                       def = 0;
+                       break;
+               }
+               else if ((c == ' ' || c == '\n') && (def != -1))
+                       break;
+       }
+       if (def)
+               printf ("yes\n\n");
+       else
+               printf ("no\n\n");
+       tcsetattr (0, TCSANOW, &termios);
+       return def;
+}
+
+int ask (const char * string, int def)
+{
+       if (nflag) {
+               printf ("%s? no\n\n", string);
+               return 0;
+       }
+       if (yflag) {
+               printf ("%s? yes\n\n", string);
+               return 1;
+       }
+       if (preen) {
+               printf ("%s? %s\n\n", string, def ? "yes" : "no");
+               return def;
+       }
+       return ask_yn(string, def);
+}
+
+void read_bitmaps(ext2_filsys fs)
+{
+       errcode_t       retval;
+
+       if (!fs->inode_map) {
+               ehandler_operation("reading inode bitmaps");
+               retval = ext2fs_read_inode_bitmap(fs);
+               ehandler_operation(0);
+               if (retval) {
+                       com_err(program_name, retval,
+                               "while retrying to read inode bitmaps for %s",
+                               device_name);
+                       fatal_error(0);
+               }
+       }
+       
+       if (!fs->block_map) {
+               ehandler_operation("reading block bitmaps");
+               retval = ext2fs_read_block_bitmap(fs);
+               ehandler_operation(0);
+               if (retval) {
+                       com_err(program_name, retval,
+                               "while retrying to read block bitmaps for %s",
+                               device_name);
+                       fatal_error(0);
+               }
+       }
+}
+
+void write_bitmaps(ext2_filsys fs)
+{
+       errcode_t       retval;
+
+       if (ext2fs_test_bb_dirty(fs)) {
+               ehandler_operation("writing block bitmaps");
+               retval = ext2fs_write_block_bitmap(fs);
+               ehandler_operation(0);
+               if (retval) {
+                       com_err(program_name, retval,
+                               "while retrying to write block bitmaps for %s",
+                               device_name);
+                       fatal_error(0);
+               }
+       }
+
+       if (ext2fs_test_ib_dirty(fs)) {
+               ehandler_operation("writing inode bitmaps");
+               retval = ext2fs_write_inode_bitmap(fs);
+               ehandler_operation(0);
+               if (retval) {
+                       com_err(program_name, retval,
+                               "while retrying to write inode bitmaps for %s",
+                               device_name);
+                       fatal_error(0);
+               }
+       }
+}
+
+void preenhalt(NOARGS)
+{
+       if (!preen)
+               return;
+       fprintf(stderr, "\n\n%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
+              device_name);
+       exit(FSCK_UNCORRECTED);
+}
+
+void init_resource_track(struct resource_track *track)
+{
+       struct rusage r;
+       
+       track->brk_start = sbrk(0);
+       gettimeofday(&track->time_start, 0);
+       getrusage(RUSAGE_SELF, &r);
+       track->user_start = r.ru_utime;
+       track->system_start = r.ru_stime;
+}
+
+static __inline__ float timeval_subtract(struct timeval *tv1,
+                                        struct timeval *tv2)
+{
+       return ((tv1->tv_sec - tv2->tv_sec) +
+               ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
+}
+
+void print_resource_track(struct resource_track *track)
+{
+       struct rusage r;
+       struct timeval time_end;
+
+       gettimeofday(&time_end, 0);
+       getrusage(RUSAGE_SELF, &r);
+
+       printf("Memory used: %d, elapsed time: %6.3f/%6.3f/%6.3f\n",
+              (int) (((char *) sbrk(0)) - ((char *) track->brk_start)),
+              timeval_subtract(&time_end, &track->time_start),
+              timeval_subtract(&r.ru_utime, &track->user_start),
+              timeval_subtract(&r.ru_stime, &track->system_start));
+}
+
+/*
+ * This function returns 1 if the inode's block entries actually
+ * contain block entries.
+ */
+int inode_has_valid_blocks(struct ext2_inode *inode)
+{
+       /*
+        * Only directories, regular files, and some symbolic links
+        * have valid block entries.
+        */
+       if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
+           !S_ISLNK(inode->i_mode))
+               return 0;
+       
+       /*
+        * If the symbolic link is a "fast symlink", then the symlink
+        * target is stored in the block entries.
+        */
+       if (S_ISLNK (inode->i_mode) && inode->i_blocks == 0 &&
+           inode->i_size < EXT2_N_BLOCKS * sizeof (unsigned long))
+               return 0;
+
+       return 1;
+}
+
+#ifdef MTRACE
+void mtrace_print(char *mesg)
+{
+       FILE    *malloc_get_mallstream();
+       FILE    *f = malloc_get_mallstream();
+
+       if (f)
+               fprintf(f, "============= %s\n", mesg);
+}
+#endif
+
+
diff --git a/lib/e2p/.depend b/lib/e2p/.depend
new file mode 100644 (file)
index 0000000..12950ef
--- /dev/null
@@ -0,0 +1,77 @@
+fgetflags.o : fgetflags.c /usr/include/errno.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/linux/errno.h /usr/include/fcntl.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/linux/fcntl.h /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/sys/ioctl.h \
+  /usr/include/linux/ioctl.h /usr/include/termios.h /usr/include/linux/termios.h \
+  /usr/include/linux/ext2_fs.h e2p.h /usr/include/dirent.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h 
+fgetversion.o : fgetversion.c /usr/include/errno.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/linux/errno.h /usr/include/fcntl.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/linux/fcntl.h /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/sys/ioctl.h \
+  /usr/include/linux/ioctl.h /usr/include/termios.h /usr/include/linux/termios.h \
+  /usr/include/linux/ext2_fs.h e2p.h /usr/include/dirent.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h 
+fsetflags.o : fsetflags.c /usr/include/errno.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/linux/errno.h /usr/include/fcntl.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/linux/fcntl.h /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/sys/ioctl.h \
+  /usr/include/linux/ioctl.h /usr/include/termios.h /usr/include/linux/termios.h \
+  /usr/include/linux/ext2_fs.h e2p.h /usr/include/dirent.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h 
+fsetversion.o : fsetversion.c /usr/include/errno.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/linux/errno.h /usr/include/fcntl.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/linux/fcntl.h /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/sys/ioctl.h \
+  /usr/include/linux/ioctl.h /usr/include/termios.h /usr/include/linux/termios.h \
+  /usr/include/linux/ext2_fs.h e2p.h /usr/include/dirent.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h 
+getflags.o : getflags.c /usr/include/errno.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/linux/errno.h /usr/include/sys/ioctl.h /usr/include/linux/ioctl.h \
+  /usr/include/termios.h /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/termios.h \
+  /usr/include/linux/ext2_fs.h e2p.h /usr/include/dirent.h /usr/include/gnu/types.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h 
+getversion.o : getversion.c /usr/include/errno.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/linux/errno.h /usr/include/sys/ioctl.h /usr/include/linux/ioctl.h \
+  /usr/include/termios.h /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/termios.h \
+  /usr/include/linux/ext2_fs.h e2p.h /usr/include/dirent.h /usr/include/gnu/types.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h 
+iod.o : iod.c /usr/include/dirent.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h e2p.h /usr/include/stdio.h /usr/include/libio.h \
+  /usr/include/_G_config.h /usr/include/linux/ext2_fs.h 
+ls.o : ls.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/time.h /usr/include/linux/ext2_fs.h \
+  e2p.h /usr/include/dirent.h /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h 
+pe.o : pe.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/linux/ext2_fs.h e2p.h \
+  /usr/include/dirent.h /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h 
+pf.o : pf.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/linux/ext2_fs.h e2p.h \
+  /usr/include/dirent.h /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h 
+ps.o : ps.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/linux/ext2_fs.h e2p.h \
+  /usr/include/dirent.h /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h 
+setflags.o : setflags.c /usr/include/errno.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/linux/errno.h /usr/include/sys/ioctl.h /usr/include/linux/ioctl.h \
+  /usr/include/termios.h /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/termios.h \
+  /usr/include/linux/ext2_fs.h e2p.h /usr/include/dirent.h /usr/include/gnu/types.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h 
+setversion.o : setversion.c /usr/include/errno.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/linux/errno.h /usr/include/sys/ioctl.h /usr/include/linux/ioctl.h \
+  /usr/include/termios.h /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/termios.h \
+  /usr/include/linux/ext2_fs.h e2p.h /usr/include/dirent.h /usr/include/gnu/types.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h 
diff --git a/lib/e2p/Makefile b/lib/e2p/Makefile
new file mode 100644 (file)
index 0000000..e890bb5
--- /dev/null
@@ -0,0 +1,66 @@
+# Makefile for the second extended file system utility functions
+#
+# Copyright (C) 1993 Remy Card (card@masi.ibp.fr)
+#
+# This file can be redistributed under the terms of the GNU General
+# Public License
+
+include ../../MCONFIG
+
+CFLAGS_NO=     $(WFLAGS) -I..
+CFLAGS=                $(OPT) $(CFLAGS_NO)
+LDFLAGS=       $(OPT)
+
+ARCHIVE=ar r
+RANLIB=ranlib
+RM=rm -f
+MV=mv
+LN=ln -s
+
+OBJS=          fgetflags.o fsetflags.o fgetversion.o fsetversion.o \
+               getflags.o getversion.o iod.o ls.o pe.o pf.o ps.o \
+               setflags.o setversion.o
+
+.c.o:
+       $(CC) $(CFLAGS) -c $*.c
+       $(CC) $(CFLAGS_NO) -pg -o profiled/$*.o -c $*.c
+#      $(CC) $(CFLAGS_NO) -checker -g -o checker/$*.o -c $*.c
+all: libe2p.a libe2p_p.a
+
+libe2p.a: $(OBJS)
+       $(RM) $@.bak
+       -$(MV) $@ $@.bak
+       $(ARCHIVE) $@ $(OBJS)
+       $(RANLIB) $@
+       $(RM) ../$@
+       $(LN) e2p/$@ ../$@
+
+libe2p_p.a: $(OBJS)
+       $(RM) $@.bak
+       -$(MV) $@ $@.bak
+       (cd profiled; $(ARCHIVE) ../$@ $(OBJS))
+       $(RANLIB) $@
+       $(RM) ../$@
+       $(LN) e2p/$@ ../$@
+
+libe2p_chk.a: $(OBJS)
+       $(RM) $@.bak
+       -$(MV) $@ $@.bak
+       (cd checker; $(ARCHIVE) ../$@ $(OBJS))
+       $(RANLIB) $@
+       $(RM) ../$@
+       $(LN) e2p/$@ ../$@
+
+install:
+
+clean:
+       rm -f \#* *.s *.o *.a *~ *.bak core profiled/* checker/*
+
+really-clean: clean
+       rm -f .depend
+
+dep depend .depend:
+       $(CC) -M $(CFLAGS) *.c >.depend
+
+include .depend
diff --git a/lib/e2p/e2p.h b/lib/e2p/e2p.h
new file mode 100644 (file)
index 0000000..d459e87
--- /dev/null
@@ -0,0 +1,20 @@
+#include <dirent.h>
+#include <stdio.h>
+
+#include <linux/ext2_fs.h>
+
+int fgetflags (const char * name, unsigned long * flags);
+int fgetversion (const char * name, unsigned long * version);
+int fsetflags (const char * name, unsigned long flags);
+int fsetversion (const char * name, unsigned long version);
+int getflags (int fd, unsigned long * flags);
+int getversion (int fd, unsigned long * version);
+int iterate_on_dir (const char * dir_name,
+                   int (*func) (const char *, struct dirent *, void *),
+                   void * private);
+void list_super (struct ext2_super_block * s);
+void print_fs_errors (FILE * f, unsigned short errors);
+void print_flags (FILE * f, unsigned long flags);
+void print_fs_state (FILE * f, unsigned short state);
+int setflags (int fd, unsigned long flags);
+int setversion (int fd, unsigned long version);
diff --git a/lib/e2p/fgetflags.c b/lib/e2p/fgetflags.c
new file mode 100644 (file)
index 0000000..95b0bdc
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * fgetflags.c         - Get a file flags 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30    - Creation
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+int fgetflags (const char * name, unsigned long * flags)
+{
+       int fd;
+       int r;
+
+       fd = open (name, O_RDONLY);
+       if (fd == -1)
+               return -1;
+       r = ioctl (fd, EXT2_IOC_GETFLAGS, flags);
+       close (fd);
+       return r;
+}
diff --git a/lib/e2p/fgetversion.c b/lib/e2p/fgetversion.c
new file mode 100644 (file)
index 0000000..73429f2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * fgetversion.c       - Get a file version 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30    - Creation
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+int fgetversion (const char * name, unsigned long * version)
+{
+       int fd;
+       int r;
+
+       fd = open (name, O_RDONLY);
+       if (fd == -1)
+               return - 1;
+       r = ioctl (fd, EXT2_IOC_GETVERSION, version);
+       close (fd);
+       return r;
+}
diff --git a/lib/e2p/fsetflags.c b/lib/e2p/fsetflags.c
new file mode 100644 (file)
index 0000000..180d48f
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * fsetflags.c         - Set a file flags 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30    - Creation
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+int fsetflags (const char * name, unsigned long flags)
+{
+       int fd;
+       int r;
+
+       fd = open (name, O_RDONLY);
+       if (fd == -1)
+               return -1;
+       r = ioctl (fd, EXT2_IOC_SETFLAGS, &flags);
+       close (fd);
+       return r;
+}
diff --git a/lib/e2p/fsetversion.c b/lib/e2p/fsetversion.c
new file mode 100644 (file)
index 0000000..1bb8acc
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * fsetversion.c       - Set a file version 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30    - Creation
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+int fsetversion (const char * name, unsigned long version)
+{
+       int fd;
+       int r;
+
+       fd = open (name, O_RDONLY);
+       if (fd == -1)
+               return -1;
+       r = ioctl (fd, EXT2_IOC_SETVERSION, &version);
+       close (fd);
+       return r;
+}
diff --git a/lib/e2p/getflags.c b/lib/e2p/getflags.c
new file mode 100644 (file)
index 0000000..4e53749
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * getflags.c          - Get a file flags 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30    - Creation
+ */
+
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+int getflags (int fd, unsigned long * flags)
+{
+       return ioctl (fd, EXT2_IOC_GETFLAGS, flags);
+}
diff --git a/lib/e2p/getversion.c b/lib/e2p/getversion.c
new file mode 100644 (file)
index 0000000..04dc0f7
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * getversion.c                - Get a file version 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30    - Creation
+ */
+
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+int getversion (int fd, unsigned long * version)
+{
+       return ioctl (fd, EXT2_IOC_GETVERSION, version);
+}
diff --git a/lib/e2p/iod.c b/lib/e2p/iod.c
new file mode 100644 (file)
index 0000000..52c16a1
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * iod.c               - Iterate a function on each entry of a directory
+ *
+ * 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30    - Creation
+ */
+
+#include <dirent.h>
+
+#include "e2p.h"
+
+int iterate_on_dir (const char * dir_name,
+                   int (*func) (const char *, struct dirent *, void *),
+                   void * private)
+{
+       DIR * dir;
+       struct dirent de;
+       struct dirent *dep;
+
+       dir = opendir (dir_name);
+       if (dir == NULL)
+               return -1;
+       while ((dep = readdir (dir)))
+       {
+               de.d_ino = dep->d_ino;
+               de.d_off = dep->d_off;
+               de.d_reclen = dep->d_reclen;
+               strcpy (de.d_name, dep->d_name);
+               (*func) (dir_name, &de, private);
+       }
+       closedir (dir);
+       return 0;
+}
diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c
new file mode 100644 (file)
index 0000000..982f044
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * ls.c                        - List the contents of an ext2fs superblock
+ *
+ * Copyright (C) 1992, 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 Library General
+ * Public License
+ */
+
+#include <stdio.h>
+#include <time.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+void list_super (struct ext2_super_block * s)
+{
+       printf ("Filesystem magic number:  0x%04X\n", s->s_magic);
+       printf ("Filesystem state:        ");
+       print_fs_state (stdout, s->s_state);
+       printf ("\n");
+       printf ("Errors behavior:          ");
+       print_fs_errors (stdout, s->s_errors);
+       printf ("\n");
+       printf ("Inode count:              %lu\n", s->s_inodes_count);
+       printf ("Block count:              %lu\n", s->s_blocks_count);
+       printf ("Reserved block count:     %lu\n", s->s_r_blocks_count);
+       printf ("Free blocks:              %lu\n", s->s_free_blocks_count);
+       printf ("Free inodes:              %lu\n", s->s_free_inodes_count);
+       printf ("First block:              %lu\n", s->s_first_data_block);
+       printf ("Block size:               %u\n", EXT2_BLOCK_SIZE(s));
+       printf ("Fragment size:            %u\n", EXT2_FRAG_SIZE(s));
+       printf ("Blocks per group:         %lu\n", s->s_blocks_per_group);
+       printf ("Fragments per group:      %lu\n", s->s_frags_per_group);
+       printf ("Inodes per group:         %lu\n", s->s_inodes_per_group);
+       printf ("Last mount time:          %s", ctime ((time_t *) &s->s_mtime));
+       printf ("Last write time:          %s", ctime ((time_t *) &s->s_wtime));
+       printf ("Mount count:              %u\n", s->s_mnt_count);
+       printf ("Maximum mount count:      %d\n", s->s_max_mnt_count);
+       printf ("Last checked:             %s", ctime ((time_t *) &s->s_lastcheck));
+       printf ("Check interval:           %lu\n", s->s_checkinterval);
+       if (s->s_checkinterval)
+       {
+               time_t next;
+
+               next = s->s_lastcheck + s->s_checkinterval;
+               printf ("Next check after:         %s", ctime (&next));
+       }
+}
diff --git a/lib/e2p/pe.c b/lib/e2p/pe.c
new file mode 100644 (file)
index 0000000..efc74b3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * pe.c                        - Print a second extended filesystem errors behavior
+ *
+ * Copyright (C) 1992, 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 94/01/09    - Creation
+ */
+
+#include <stdio.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+void print_fs_errors (FILE * f, unsigned short errors)
+{
+       switch (errors)
+       {
+               case EXT2_ERRORS_CONTINUE:
+                       fprintf (f, "Continue");
+                       break;
+               case EXT2_ERRORS_RO:
+                       fprintf (f, "Remount read-only");
+                       break;
+               case EXT2_ERRORS_PANIC:
+                       fprintf (f, "Panic");
+                       break;
+               default:
+                       fprintf (f, "Unknown (continue)");
+       }
+}
diff --git a/lib/e2p/pf.c b/lib/e2p/pf.c
new file mode 100644 (file)
index 0000000..58f05de
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * pf.c                        - Print 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30    - Creation
+ */
+
+#include <stdio.h>
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+void print_flags (FILE * f, unsigned long flags)
+{
+       if (flags & EXT2_SYNC_FL)
+               fprintf (f, "S");
+       else
+               fprintf (f, "-");
+       if (flags & EXT2_COMPR_FL)
+               fprintf (f, "c");
+       else
+               fprintf (f, "-");
+       if (flags & EXT2_SECRM_FL)
+               fprintf (f, "s");
+       else
+               fprintf (f, "-");
+       if (flags & EXT2_UNRM_FL)
+               fprintf (f, "u");
+       else
+               fprintf (f, "-");
+}
diff --git a/lib/e2p/ps.c b/lib/e2p/ps.c
new file mode 100644 (file)
index 0000000..441d6dc
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * ps.c                        - Print filesystem state
+ *
+ * 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/12/22    - Creation
+ */
+
+#include <stdio.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+void print_fs_state (FILE * f, unsigned short state)
+{
+       if (state & EXT2_VALID_FS)
+               fprintf (f, " clean");
+       else
+               fprintf (f, " not clean");
+       if (state & EXT2_ERROR_FS)
+               fprintf (f, " with errors");
+}
diff --git a/lib/e2p/setflags.c b/lib/e2p/setflags.c
new file mode 100644 (file)
index 0000000..c1e9fcb
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * setflags.c          - Set a file flags 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30    - Creation
+ */
+
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+int setflags (int fd, unsigned long flags)
+{
+       return ioctl (fd, EXT2_IOC_SETFLAGS, &flags);
+}
diff --git a/lib/e2p/setversion.c b/lib/e2p/setversion.c
new file mode 100644 (file)
index 0000000..a6da31e
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * setversion.c                - Set a file version 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 Library General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/10/30    - Creation
+ */
+
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <linux/ext2_fs.h>
+
+#include "e2p.h"
+
+int setversion (int fd, unsigned long version)
+{
+       return ioctl (fd, EXT2_IOC_SETVERSION, &version);
+}
diff --git a/lib/et/.depend b/lib/et/.depend
new file mode 100644 (file)
index 0000000..c0ebdfb
--- /dev/null
@@ -0,0 +1,13 @@
+com_err.o : com_err.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h mit-sipb-copyright.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  error_table.h internal.h /usr/include/errno.h /usr/include/linux/errno.h com_err.h 
+error_message.o : error_message.c /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h error_table.h mit-sipb-copyright.h \
+  internal.h /usr/include/errno.h /usr/include/linux/errno.h 
+et_name.o : et_name.c error_table.h mit-sipb-copyright.h internal.h /usr/include/errno.h \
+  /usr/include/features.h /usr/include/sys/cdefs.h /usr/include/linux/errno.h 
+init_et.o : init_et.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h error_table.h mit-sipb-copyright.h 
+vfprintf.o : vfprintf.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/varargs.h 
diff --git a/lib/et/Makefile b/lib/et/Makefile
new file mode 100644 (file)
index 0000000..6b4cd47
--- /dev/null
@@ -0,0 +1,85 @@
+include ../../MCONFIG
+
+ARCHIVE=ar r
+RANLIB=ranlib
+RM=rm -f
+MV=mv
+LN=ln -s
+TAGS=etags
+
+CFLAGS_NO=
+CFLAGS= $(CFLAGS_NO) $(OPT)
+
+OBJS= error_message.o et_name.o init_et.o com_err.o
+SRCS = error_message.c et_name.c init_et.c com_err.c
+
+HFILES= com_err.h
+
+#
+# what to build...
+#
+
+.c.o:
+       $(CC) $(CFLAGS) -c $*.c
+       $(CC) $(CFLAGS_NO) -g -pg -o profiled/$*.o -c $*.c
+
+all: compile_et libcom_err.a libcom_err_p.a
+
+compile_et: compile_et.sh
+       ./config_script compile_et.sh $(AWK) > compile_et
+       chmod +x compile_et
+
+libcom_err.a: $(OBJS)
+       $(RM) $@.bak
+       -$(MV) $@ $@.bak
+       $(ARCHIVE) $@ $(OBJS)
+       $(RANLIB) $@
+       $(RM) ../$@
+       $(LN) et/$@ ../$@
+
+libcom_err_p.a: $(OBJS)
+       $(RM) $@.bak
+       -$(MV) $@ $@.bak
+       (cd profiled ; $(ARCHIVE) ../$@ $(OBJS))
+       $(RANLIB) $@
+       $(RM) ../$@
+       $(LN) et/$@ ../$@
+
+clean:
+       $(RM) compile_et libcom_err.a libcom_err_p.a
+       $(RM) $(OBJS) profiled/*
+       $(RM) *~ \#* *.bak *.otl *.aux *.toc *.PS *.dvi *.ps TAGS *.ln
+
+really-clean: clean
+       $(RM) .depend
+
+install:: libcom_err.a
+       $(INSTALLLIB) libcom_err.a $(DESTDIR)$(LIBDIR)/libcom_err.a
+       $(CHMOD) 644 $(DESTDIR)$(LIBDIR)/libcom_err.a
+       $(RANLIB)    $(DESTDIR)$(LIBDIR)/libcom_err.a
+       $(CHMOD) $(LIBMODE) $(DESTDIR)$(LIBDIR)/libcom_err.a
+
+install:: $(HFILES)
+       @rm -rf ${DESTDIR}$(INCLDIR)/et
+       @mkdir ${DESTDIR}$(INCLDIR)/et
+       for i in $(HFILES); do \
+               $(INSTALLINC) $$i ${DESTDIR}$(INCLDIR)/et/$$i; \
+       done
+
+## 
+
+com_err.ps : com_err.dvi
+com_err.dvi: com_err.texinfo
+
+libcom_err.o:  $(LIBOBJS)
+       ld -r -s -o libcom_err.o $(LIBOBJS)
+       chmod -x libcom_err.o
+
+
+TAGS:  $(SRCS)
+       $(TAGS) $(SRCS)
+
+dep depend .depend: compile_et
+       $(CPP) -M $(CFLAGS) *.c >.depend
+
+include .depend
diff --git a/lib/et/com_err.3 b/lib/et/com_err.3
new file mode 100644 (file)
index 0000000..ee4375b
--- /dev/null
@@ -0,0 +1,96 @@
+.\" Copyright (c) 1988 Massachusetts Institute of Technology,
+.\" Student Information Processing Board.  All rights reserved.
+.\"
+.\" $Header$
+.\"
+.TH COM_ERR 3 "22 Nov 1988" SIPB
+.SH NAME
+com_err \- common error display routine
+.SH SYNOPSIS
+.nf
+ #include <com_err.h>
+.PP
+void com_err (whoami, code, format, ...);
+       const char *whoami;
+       long code;
+       const char *format;
+.PP
+proc = set_com_err_hook (proc);
+.fi
+void (*
+.I proc
+) (const char *, long, const char *, va_list);
+.nf
+.PP
+proc = reset_com_err_hook ();
+.PP
+void initialize_XXXX_error_table ();
+.fi
+.SH DESCRIPTION
+.I Com_err
+displays an error message on the standard error stream
+.I stderr
+(see
+.IR stdio (3S))
+composed of the
+.I whoami
+string, which should specify the program name or some subportion of
+a program, followed by an error message generated from the
+.I code
+value (derived from
+.IR compile_et (1)),
+and a string produced using the
+.I format
+string and any following arguments, in the same style as
+.IR fprintf (3).
+
+The behavior of
+.I com_err
+can be modified using
+.I set_com_err_hook;
+this defines a procedure which is called with the arguments passed to
+.I com_err,
+instead of the default internal procedure which sends the formatted
+text to error output.  Thus the error messages from a program can all
+easily be diverted to another form of diagnostic logging, such as
+.IR syslog (3).
+.I Reset_com_err_hook
+may be used to restore the behavior of
+.I com_err
+to its default form.  Both procedures return the previous ``hook''
+value.  These ``hook'' procedures must have the declaration given for
+.I proc
+above in the synopsis.
+
+The
+.I initialize_XXXX_error_table
+routine is generated mechanically by
+.IR compile_et (1)
+from a source file containing names and associated strings.  Each
+table has a name of up to four characters, which is used in place of
+the
+.B XXXX
+in the name of the routine.  These routines should be called before
+any of the corresponding error codes are used, so that the
+.I com_err
+library will recognize error codes from these tables when they are
+used.
+
+The
+.B com_err.h
+header file should be included in any source file that uses routines
+from the
+.I com_err
+library; executable files must be linked using
+.I ``-lcom_err''
+in order to cause the
+.I com_err
+library to be included.
+
+.\" .IR for manual entries
+.\" .PP for paragraph breaks
+
+.SH "SEE ALSO"
+compile_et (1), syslog (3).
+
+Ken Raeburn, "A Common Error Description Library for UNIX".
diff --git a/lib/et/com_err.c b/lib/et/com_err.c
new file mode 100644 (file)
index 0000000..9f4ba5f
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board.
+ *
+ * For copyright info, see mit-sipb-copyright.h.
+ */
+
+#include <stdio.h>
+#include "mit-sipb-copyright.h"
+
+#if __STDC__ || defined(STDARG_PROTOTYPES)
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#define VARARGS
+#endif
+
+#include "error_table.h"
+#include "internal.h"
+
+#ifdef notdef
+/*
+ * Protect us from header version (externally visible) of com_err, so
+ * we can survive in a <varargs.h> environment.  I think.
+ */
+#define com_err com_err_external
+#include "com_err.h"
+#undef com_err
+#else
+#include "com_err.h"
+#endif
+
+#if ! lint
+static const char rcsid[] =
+    "$Header$";
+#endif /* ! lint */
+
+static void
+#ifdef __STDC__
+    default_com_err_proc (const char *whoami, long code, const char *fmt, va_list args)
+#else
+    default_com_err_proc (whoami, code, fmt, args)
+    const char *whoami;
+    long code;
+    const char *fmt;
+    va_list args;
+#endif
+{
+    if (whoami) {
+       fputs(whoami, stderr);
+       fputs(": ", stderr);
+    }
+    if (code) {
+       fputs(error_message(code), stderr);
+       fputs(" ", stderr);
+    }
+    if (fmt) {
+        vfprintf (stderr, fmt, args);
+    }
+    putc('\n', stderr);
+    /* should do this only on a tty in raw mode */
+    putc('\r', stderr);
+    fflush(stderr);
+}
+
+#ifdef __STDC__
+typedef void (*errf) (const char *, long, const char *, va_list);
+#else
+typedef void (*errf) ();
+#endif
+
+errf com_err_hook = default_com_err_proc;
+
+void com_err_va (whoami, code, fmt, args)
+    const char *whoami;
+    long code;
+    const char *fmt;
+    va_list args;
+{
+    (*com_err_hook) (whoami, code, fmt, args);
+}
+
+#ifndef VARARGS
+void com_err (const char *whoami,
+             long code,
+             const char *fmt, ...)
+{
+#else
+void com_err (va_alist)
+    va_dcl
+{
+    const char *whoami, *fmt;
+    long code;
+#endif
+    va_list pvar;
+
+    if (!com_err_hook)
+       com_err_hook = default_com_err_proc;
+#ifdef VARARGS
+    va_start (pvar);
+    whoami = va_arg (pvar, const char *);
+    code = va_arg (pvar, long);
+    fmt = va_arg (pvar, const char *);
+#else
+    va_start(pvar, fmt);
+#endif
+    com_err_va (whoami, code, fmt, pvar);
+    va_end(pvar);
+}
+
+errf set_com_err_hook (new_proc)
+    errf new_proc;
+{
+    errf x = com_err_hook;
+
+    if (new_proc)
+       com_err_hook = new_proc;
+    else
+       com_err_hook = default_com_err_proc;
+
+    return x;
+}
+
+errf reset_com_err_hook () {
+    errf x = com_err_hook;
+    com_err_hook = default_com_err_proc;
+    return x;
+}
diff --git a/lib/et/com_err.h b/lib/et/com_err.h
new file mode 100644 (file)
index 0000000..54904c3
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Header file for common error description library.
+ *
+ * Copyright 1988, Student Information Processing Board of the
+ * Massachusetts Institute of Technology.
+ *
+ * For copyright and distribution info, see the documentation supplied
+ * with this package.
+ */
+
+#ifndef __COM_ERR_H
+
+typedef long errcode_t;
+
+#ifdef __STDC__
+#ifndef __HIGHC__              /* gives us STDC but not stdarg */
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+/* ANSI C -- use prototypes etc */
+void com_err (const char *, long, const char *, ...);
+char const *error_message (long);
+void (*com_err_hook) (const char *, long, const char *, va_list);
+void (*set_com_err_hook (void (*) (const char *, long, const char *, va_list)))
+    (const char *, long, const char *, va_list);
+void (*reset_com_err_hook (void)) (const char *, long, const char *, va_list);
+#else
+/* no prototypes */
+void com_err ();
+char *error_message ();
+void (*com_err_hook) ();
+void (*set_com_err_hook ()) ();
+void (*reset_com_err_hook ()) ();
+#endif
+
+#define __COM_ERR_H
+#endif /* ! defined(__COM_ERR_H) */
diff --git a/lib/et/com_err.texinfo b/lib/et/com_err.texinfo
new file mode 100644 (file)
index 0000000..2f4b266
--- /dev/null
@@ -0,0 +1,554 @@
+\input texinfo @c -*-texinfo-*-
+
+@c $Header$
+@c $Source$
+@c $Locker$
+
+@c Note that although this source file is in texinfo format (more
+@c or less), it is not yet suitable for turning into an ``info''
+@c file.  Sorry, maybe next time.
+@c
+@c In order to produce hardcopy documentation from a texinfo file,
+@c run ``tex com_err.texinfo'' which will load in texinfo.tex,
+@c provided in this distribution.  (texinfo.tex is from the Free
+@c Software Foundation, and is under different copyright restrictions
+@c from the rest of this package.)
+
+@ifinfo
+@barfo
+@end ifinfo
+
+@iftex
+@tolerance 10000
+
+@c Mutate section headers...
+@begingroup
+  @catcode\11#=6
+  @gdef@secheading#1#2#3{@secheadingi {#3@enspace #1}}
+@endgroup
+@end iftex
+
+@setfilename com_err
+@settitle A Common Error Description Library for UNIX
+
+@ifinfo
+This file documents the use of the Common Error Description library.
+
+Copyright (C) 1987, 1988 Student Information Processing Board of the
+Massachusetts Institute of Technology.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.  M.I.T. and the M.I.T. S.I.P.B.
+make no representations about the suitability of this software for any
+purpose.  It is provided "as is" without express or implied warranty.
+
+Note that the file texinfo.tex, provided with this distribution, is from
+the Free Software Foundation, and is under different copyright restrictions
+from the remainder of this package.
+
+@end ifinfo
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+
+@setchapternewpage odd
+
+@titlepage
+@center @titlefont{A Common Error Description}
+@center @titlefont{Library for UNIX}
+@sp 2
+@center Ken Raeburn
+@center Bill Sommerfeld
+@sp 1
+@center MIT Student Information Processing Board
+@sp 3
+@center last updated 1 January 1989
+@center for version 1.2
+@center ***DRAFT COPY ONLY***
+
+@vskip 2in
+
+@center @b{Abstract}
+
+UNIX has always had a clean and simple system call interface, with a
+standard set of error codes passed between the kernel and user
+programs.  Unfortunately, the same cannot be said of many of the
+libraries layered on top of the primitives provided by the kernel.
+Typically, each one has used a different style of indicating errors to
+their callers, leading to a total hodgepodge of error handling, and
+considerable amounts of work for the programmer.  This paper describes
+a library and associated utilities which allows a more uniform way for
+libraries to return errors to their callers, and for programs to
+describe errors and exceptional conditions to their users.
+
+@page
+@vskip 0pt plus 1filll
+
+Copyright @copyright{} 1987, 1988 by the Student Information Processing
+Board of the Massachusetts Institute of Technology.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.  M.I.T. and the M.I.T. S.I.P.B.
+make no representations about the suitability of this software for any
+purpose.  It is provided "as is" without express or implied warranty.
+
+Note that the file texinfo.tex, provided with this distribution, is from
+the Free Software Foundation, and is under different copyright restrictions
+from the remainder of this package.
+
+@end titlepage
+
+@ifinfo
+@c should put a menu here someday....
+@end ifinfo
+
+@page
+
+@section Why com_err?
+
+In building application software packages, a programmer often has to
+deal with a number of libraries, each of which can use a different
+error-reporting mechanism.  Sometimes one of two values is returned,
+indicating simply SUCCESS or FAILURE, with no description of errors
+encountered.  Sometimes it is an index into a table of text strings,
+where the name of the table used is dependent on the library being
+used when the error is generated; since each table starts numbering at
+0 or 1, additional information as to the source of the error code is
+needed to determine which table to look at.  Sometimes no text messages are
+supplied at all, and the programmer must supply them at any point at which
+he may wish to report error conditions.
+Often, a global variable is assigned some value describing the error, but
+the programmer has to know in each case whether to look at @code{errno},
+@code{h_errno}, the return value from @code{hes_err()}, or whatever other
+variables or routines are specified.
+And what happens if something
+in the procedure of
+examining or reporting the error changes the same variable?
+
+The package we have developed is an attempt to present a common
+error-handling mechanism to manipulate the most common form of error code
+in a fashion that does not have the problems listed above.
+
+A list of up to 256 text messages is supplied to a translator we have
+written, along with the three- to four-character ``name'' of the error
+table.  The library using this error table need only call a routine
+generated from this error-table source to make the table ``known'' to the
+com_err library, and any error code the library generates can be converted
+to the corresponding error message.  There is also a default format for
+error codes accidentally returned before making the table known, which is
+of the form @samp{unknown code foo 32}, where @samp{foo} would be the name
+of the table.
+
+@section Error codes
+
+Error codes themselves are 32 bit (signed) integers, of which the high
+order 24 bits are an identifier of which error table the error code is
+from, and the low order 8 bits are a sequential error number within
+the table.  An error code may thus be easily decomposed into its component
+parts.  Only the lowest 32 bits of an error code are considered significant
+on systems which support wider values.
+
+Error table 0 is defined to match the UNIX system call error table
+(@code{sys_errlist}); this allows @code{errno} values to be used directly
+in the library (assuming that @code{errno} is of a type with the same width
+as @t{long}).  Other error table numbers are formed by compacting together
+the first four characters of the error table name.  The mapping between
+characters in the name and numeric values in the error code are defined in
+a system-independent fashion, so that two systems that can pass integral
+values between them can reliably pass error codes without loss of meaning;
+this should work even if the character sets used are not the same.
+(However, if this is to be done, error table 0 should be avoided, since the
+local system call error tables may differ.)
+
+Any variable which is to contain an error code should be declared @t{long}.
+The draft proposed American National Standard for C (as of May, 1988)
+requires that @t{long} variables be at least 32 bits; any system which does
+not support 32-bit @t{long} values cannot make use of this package (nor
+much other software that assumes an ANSI-C environment base) without
+significant effort.
+
+@section Error table source file
+
+The error table source file begins with the declaration of the table name,
+as
+
+@example
+error_table @var{tablename}
+@end example
+
+Individual error codes are
+specified with
+
+@example
+error_code @var{ERROR_NAME}, @var{"text message"}
+@end example
+
+where @samp{ec} can also be used as a short form of @samp{error_code}.  To
+indicate the end of the table, use @samp{end}.  Thus, a (short) sample
+error table might be:
+
+@example
+
+        error_table     dsc
+
+        error_code      DSC_DUP_MTG_NAME,
+                        "Meeting already exists"
+
+        ec              DSC_BAD_PATH,
+                        "A bad meeting pathname was given"
+
+        ec              DSC_BAD_MODES,
+                        "Invalid mode for this access control list"
+
+        end
+
+@end example
+
+@section The error-table compiler
+
+The error table compiler is named @code{compile_et}.  It takes one
+argument, the pathname of a file (ending in @samp{.et}, e.g.,
+@samp{dsc_err.et}) containing an error table source file.  It parses the
+error table, and generates two output files -- a C header file
+(@samp{discuss_err.h}) which contains definitions of the numerical values
+of the error codes defined in the error table, and a C source file which
+should be compiled and linked with the executable.  The header file must be
+included in the source of a module which wishes to reference the error
+codes defined; the object module generated from the C code may be linked in
+to a program which wishes to use the printed forms of the error codes.
+
+This translator accepts a @kbd{-language @var{lang}} argument, which
+determines for which language (or language variant) the output should be
+written.  At the moment, @var{lang} is currently limited to @kbd{ANSI-C}
+and @kbd{K&R-C}, and some abbreviated forms of each.  Eventually, this will
+be extended to include some support for C++.  The default is currently
+@kbd{K&R-C}, though the generated sources will have ANSI-C code
+conditionalized on the symbol @t{__STDC__}.
+
+@section Run-time support routines
+
+Any source file which uses the routines supplied with or produced by the
+com_err package should include the header file @file{<com_err.h>}.  It
+contains declarations and definitions which may be needed on some systems.
+(Some functions cannot be referenced properly without the return type
+declarations in this file.  Some functions may work properly on most
+architectures even without the header file, but relying on this is not
+recommended.)
+
+The run-time support routines and variables provided via this package
+include the following:
+
+@example
+void initialize_@var{xxxx}_error_table (void);
+@end example
+
+One of these routines is built by the error compiler for each error table.
+It makes the @var{xxxx} error table ``known'' to the error reporting
+system.  By convention, this routine should be called in the initialization
+routine of the @var{xxxx} library.  If the library has no initialization
+routine, some combination of routines which form the core of the library
+should ensure that this routine is called.  It is not advised to leave it
+the caller to make this call.
+
+There is no harm in calling this routine more than once.
+
+@example
+#define ERROR_TABLE_BASE_@var{xxxx} @var{nnnnn}L
+@end example
+
+This symbol contains the value of the first error code entry in the
+specified table.
+This rarely needs be used by the
+programmer.
+
+@example
+const char *error_message (long code);
+@end example
+
+This routine returns the character string error message associated
+with @code{code}; if this is associated with an unknown error table, or
+if the code is associated with a known error table but the code is not
+in the table, a string of the form @samp{Unknown code @var{xxxx nn}} is
+returned, where @var{xxxx} is the error table name produced by
+reversing the compaction performed on the error table number implied
+by that error code, and @var{nn} is the offset from that base value.
+
+Although this routine is available for use when needed, its use should be
+left to circumstances which render @code{com_err} (below) unusable.
+
+@example
+void com_err (const char *whoami,  /* module reporting error */
+              long code,           /* error code */
+              const char *format,  /* format for additional detail */
+              ...);                /*  (extra parameters) */
+@end example
+
+This routine provides an alternate way to print error messages to
+standard error; it allows the error message to be passed in as a
+parameter, rather than in an external variable.  @emph{Provide grammatical
+context for ``message.''}
+
+If @var{format} is @code{(char *)NULL}, the formatted message will not be
+printed.  @var{format} may not be omitted.
+
+@example
+#include <stdarg.h>
+
+void com_err_va (const char *whoami,
+                 long code,
+                 const char *format,
+                 va_list args);
+@end example
+
+This routine provides an interface, equivalent to @code{com_err} above,
+which may be used by higher-level variadic functions (functions which
+accept variable numbers of arguments).
+
+@example
+#include <stdarg.h>
+
+void (*set_com_err_hook (void (*proc) ())) ();
+
+void (*@var{proc}) (const char *whoami, long code, va_list args);
+
+void reset_com_err_hook ();
+@end example
+
+These two routines allow a routine to be dynamically substituted for
+@samp{com_err}.  After @samp{set_com_err_hook} has been called,
+calls to @samp{com_err} will turn into calls to the new hook routine.
+@samp{reset_com_err_hook} turns off this hook.  This may intended to
+be used in daemons (to use a routine which calls @var{syslog(3)}), or
+in a window system application (which could pop up a dialogue box).
+
+If a program is to be used in an environment in which simply printing
+messages to the @code{stderr} stream would be inappropriate (such as in a
+daemon program which runs without a terminal attached),
+@code{set_com_err_hook} may be used to redirect output from @code{com_err}.
+The following is an example of an error handler which uses @var{syslog(3)}
+as supplied in BSD 4.3:
+
+@example
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+/* extern openlog (const char * name, int logopt, int facility); */
+/* extern syslog (int priority, char * message, ...); */
+
+void hook (const char * whoami, long code,
+           const char * format, va_list args)
+@{
+    char buffer[BUFSIZ];
+    static int initialized = 0;
+    if (!initialized) @{
+        openlog (whoami,
+                 LOG_NOWAIT|LOG_CONS|LOG_PID|LOG_NDELAY,
+                 LOG_DAEMON);
+        initialized = 1;
+    @}
+    vsprintf (buffer, format, args);
+    syslog (LOG_ERR, "%s %s", error_message (code), buffer);
+@}
+@end example
+
+After making the call
+@code{set_com_err_hook (hook);},
+any calls to @code{com_err} will result in messages being sent to the
+@var{syslogd} daemon for logging.
+The name of the program, @samp{whoami}, is supplied to the
+@samp{openlog()} call, and the message is formatted into a buffer and
+passed to @code{syslog}.
+
+Note that since the extra arguments to @code{com_err} are passed by
+reference via the @code{va_list} value @code{args}, the hook routine may
+place any form of interpretation on them, including ignoring them.  For
+consistency, @code{printf}-style interpretation is suggested, via
+@code{vsprintf} (or @code{_doprnt} on BSD systems without full support for
+the ANSI C library).
+
+@section Coding Conventions
+
+The following conventions are just some general stylistic conventions
+to follow when writing robust libraries and programs.  Conventions
+similar to this are generally followed inside the UNIX kernel and most
+routines in the Multics operating system.  In general, a routine
+either succeeds (returning a zero error code, and doing some side
+effects in the process), or it fails, doing minimal side effects; in
+any event, any invariant which the library assumes must be maintained.
+
+In general, it is not in the domain of non user-interface library
+routines to write error messages to the user's terminal, or halt the
+process.  Such forms of ``error handling'' should be reserved for
+failures of internal invariants and consistancy checks only, as it
+provides the user of the library no way to clean up for himself in the
+event of total failure.
+
+Library routines which can fail should be set up to return an error
+code.  This should usually be done as the return value of the
+function; if this is not acceptable, the routine should return a
+``null'' value, and put the error code into a parameter passed by
+reference.
+
+Routines which use the first style of interface can be used from
+user-interface levels of a program as follows:
+
+@example
+@{
+    if ((code = initialize_world(getuid(), random())) != 0) @{
+        com_err("demo", code,
+                "when trying to initialize world");
+        exit(1);
+    @}
+    if ((database = open_database("my_secrets", &code))==NULL) @{
+        com_err("demo", code,
+                "while opening my_secrets");
+        exit(1);
+    @}
+@}
+@end example
+
+A caller which fails to check the return status is in error.  It is
+possible to look for code which ignores error returns by using lint;
+look for error messages of the form ``foobar returns value which is
+sometimes ignored'' or ``foobar returns value which is always
+ignored.''
+
+Since libraries may be built out of other libraries, it is often necessary
+for the success of one routine to depend on another.  When a lower level
+routine returns an error code, the middle level routine has a few possible
+options.  It can simply return the error code to its caller after doing
+some form of cleanup, it can substitute one of its own, or it can take
+corrective action of its own and continue normally.  For instance, a
+library routine which makes a ``connect'' system call to make a network
+connection may reflect the system error code @code{ECONNREFUSED}
+(Connection refused) to its caller, or it may return a ``server not
+available, try again later,'' or it may try a different server.
+
+Cleanup which is typically necessary may include, but not be limited
+to, freeing allocated memory which will not be needed any more,
+unlocking concurrancy locks, dropping reference counts, closing file
+descriptors, or otherwise undoing anything which the procedure did up
+to this point.  When there are a lot of things which can go wrong, it
+is generally good to write one block of error-handling code which is
+branched to, using a goto, in the event of failure.  A common source
+of errors in UNIX programs is failing to close file descriptors on
+error returns; this leaves a number of ``zombied'' file descriptors
+open, which eventually causes the process to run out of file
+descriptors and fall over.
+
+@example
+@{
+    FILE *f1=NULL, *f2=NULL, *f3=NULL;
+    int status = 0;
+
+    if ( (f1 = fopen(FILE1, "r")) == NULL) @{
+        status = errno;
+        goto error;
+    @}
+
+    /*
+     * Crunch for a while
+     */
+
+    if ( (f2 = fopen(FILE2, "w")) == NULL) @{
+        status = errno;
+        goto error;
+    @}
+
+    if ( (f3 = fopen(FILE3, "a+")) == NULL) @{
+        status = errno;
+            goto error;
+    @}
+
+    /*
+     * Do more processing.
+     */
+    fclose(f1);
+    fclose(f2);
+    fclose(f3);
+    return 0;
+
+error:
+    if (f1) fclose(f1);
+    if (f2) fclose(f2);
+    if (f3) fclose(f3);
+    return status;
+@}
+@end example
+
+@section Building and Installation
+
+The distribution of this package will probably be done as a compressed
+``tar''-format file available via anonymous FTP from SIPB.MIT.EDU.
+Retrieve @samp{pub/com_err.tar.Z} and extract the contents.  A subdirectory
+@t{profiled} should be created to hold objects compiled for profiling.
+Running ``make all'' should then be sufficient to build the library and
+error-table compiler.  The files @samp{libcom_err.a},
+@samp{libcom_err_p.a}, @samp{com_err.h}, and @samp{compile_et} should be
+installed for use; @samp{com_err.3} and @samp{compile_et.1} can also be
+installed as manual pages.
+
+Potential problems:
+
+@itemize @bullet
+
+@item Use of @code{strcasecmp}, a routine provided in BSD for
+case-insensitive string comparisons.  If an equivalent routine is
+available, you can modify @code{CFLAGS} in the makefile to define
+@code{strcasecmp} to the name of that routine.
+
+@item Compilers that defined @code{__STDC__} without providing the header
+file @code{<stdarg.h>}.  One such example is Metaware's High ``C''
+compiler, as provided at Project Athena on the IBM RT/PC workstation; if
+@code{__HIGHC__} is defined, it is assumed that @code{<stdarg.h>} is not
+available, and therefore @code{<varargs.h>} must be used.  If the symbol
+@code{VARARGS} is defined (e.g., in the makefile), @code{<varargs.h>} will
+be used.
+
+@item If your linker rejects symbols that are simultaneously defined in two
+library files, edit @samp{Makefile} to remove @samp{perror.c} from the
+library.  This file contains a version of @var{perror(3)} which calls
+@code{com_err} instead of calling @code{write} directly.
+
+@end itemize
+
+As I do not have access to non-BSD systems, there are probably
+bugs present that may interfere with building or using this package on
+other systems.  If they are reported to me, they can probably be fixed for
+the next version.
+
+@section Bug Reports
+
+Please send any comments or bug reports to the principal author: Ken
+Raeburn, @t{Raeburn@@Athena.MIT.EDU}.
+
+@section Acknowledgements
+
+I would like to thank: Bill Sommerfeld, for his help with some of this
+documentation, and catching some of the bugs the first time around;
+Honeywell Information Systems, for not killing off the @emph{Multics}
+operating system before I had an opportunity to use it; Honeywell's
+customers, who persuaded them not to do so, for a while; Ted Anderson of
+CMU, for catching some problems before version 1.2 left the nest; Stan
+Zanarotti and several others of MIT's Student Information Processing Board,
+for getting us started with ``discuss,'' for which this package was
+originally written; and everyone I've talked into --- I mean, asked to read
+this document and the ``man'' pages.
+
+@bye
diff --git a/lib/et/compile_et.1 b/lib/et/compile_et.1
new file mode 100644 (file)
index 0000000..f17a278
--- /dev/null
@@ -0,0 +1,79 @@
+.\" Copyright (c) 1988 Massachusetts Institute of Technology,
+.\" Student Information Processing Board.  All rights reserved.
+.\"
+.\" $Header$
+.\"
+.TH COMPILE_ET 1 "22 Nov 1988" SIPB
+.SH NAME
+compile_et \- error table compiler
+.SH SYNOPSIS
+.B compile_et
+file
+.SH DESCRIPTION
+.B Compile_et
+converts a table listing error-code names and associated messages into
+a C source file suitable for use with the
+.IR com_err (3)
+library.
+
+The source file name must end with a suffix of ``.et''; the file
+consists of a declaration supplying the name (up to four characters
+long) of the error-code table:
+
+.B error_table
+.I name
+
+followed by up to 256 entries of the form:
+
+.B error_code
+.I name,
+"
+.I string
+"
+
+and a final
+
+.B end
+
+to indicate the end of the table.
+
+The name of the table is used to construct the name of a subroutine
+.I initialize_XXXX_error_table
+which must be called in order for the
+.I com_err
+library to recognize the error table.
+
+The various error codes defined are assigned sequentially increasing
+numbers (starting with a large number computed as a hash function of
+the name of the table); thus for compatibility it is suggested that
+new codes be added only to the end of an existing table, and that no
+codes be removed from tables.
+
+The names defined in the table are placed into a C header file with
+preprocessor directives defining them as integer constants of up to
+32 bits in magnitude.
+
+A C source file is also generated which should be compiled and linked
+with the object files which reference these error codes; it contains
+the text of the messages and the initialization subroutine.  Both C
+files have names derived from that of the original source file, with
+the ``.et'' suffix replaced by ``.c'' and ``.h''.
+
+A ``#'' in the source file is treated as a comment character, and all
+remaining text to the end of the source line will be ignored.
+
+.SH BUGS
+
+Since
+.B compile_et
+uses a very simple parser based on
+.IR yacc (1),
+its error recovery leaves much to be desired.
+
+.\" .IR for manual entries
+.\" .PP for paragraph breaks
+
+.SH "SEE ALSO"
+com_err (3).
+
+Ken Raeburn, "A Common Error Description Library for UNIX".
diff --git a/lib/et/compile_et.sh b/lib/et/compile_et.sh
new file mode 100644 (file)
index 0000000..fdd249e
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+#
+AWK=@AWK@
+DIR=@DIR@
+
+ROOT=`echo $1 | sed -e s/.et$//`
+BASE=`basename $ROOT`
+
+$AWK -f ${DIR}/et_h.awk outfile=${BASE}.h $ROOT.et
+$AWK -f ${DIR}/et_c.awk outfile=${BASE}.c $ROOT.et
diff --git a/lib/et/config_script b/lib/et/config_script
new file mode 100644 (file)
index 0000000..e3de35c
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# This program takes a shell script and configures for the following
+# variables:   @DIR@
+#              @AWK@
+#              @SED@
+#
+# Usage: config_script <filename> [<awk>] [<sed>]
+#
+
+FILE=$1
+AWK=$2
+SED=$3
+
+# Grr.... not all Unix's have the dirname command
+TMP=`echo  $1 | sed -e 's;[^/]*$;;' -e 's/^$/./'`
+DIR=`cd ${TMP}; pwd`
+
+if test "${AWK}x" = "x" ; then
+       AWK=awk
+fi
+if test "${SED}x" = "x" ; then
+       SED=sed
+fi
+sed -e "s;@DIR@;${DIR};" -e "s;@AWK@;${AWK};" -e "s;@SED@;${SED};" $FILE
diff --git a/lib/et/error_message.c b/lib/et/error_message.c
new file mode 100644 (file)
index 0000000..043b02e
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * $Header$
+ * $Source$
+ * $Locker$
+ *
+ * Copyright 1987 by the Student Information Processing Board
+ * of the Massachusetts Institute of Technology
+ *
+ * For copyright info, see "mit-sipb-copyright.h".
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "error_table.h"
+#include "mit-sipb-copyright.h"
+#include "internal.h"
+
+static const char rcsid[] =
+    "$Header$";
+static const char copyright[] =
+    "Copyright 1986, 1987, 1988 by the Student Information Processing Board\nand the department of Information Systems\nof the Massachusetts Institute of Technology";
+
+static char buffer[25];
+
+struct et_list * _et_list = (struct et_list *) NULL;
+
+const char * error_message (code)
+long   code;
+{
+    int offset;
+    struct et_list *et;
+    int table_num;
+    int started = 0;
+    char *cp;
+
+    offset = code & ((1<<ERRCODE_RANGE)-1);
+    table_num = code - offset;
+    if (!table_num) {
+       if (offset < sys_nerr)
+           return(sys_errlist[offset]);
+       else
+           goto oops;
+    }
+    for (et = _et_list; et; et = et->next) {
+       if (et->table->base == table_num) {
+           /* This is the right table */
+           if (et->table->n_msgs <= offset)
+               goto oops;
+           return(et->table->msgs[offset]);
+       }
+    }
+oops:
+    strcpy (buffer, "Unknown code ");
+    if (table_num) {
+       strcat (buffer, error_table_name (table_num));
+       strcat (buffer, " ");
+    }
+    for (cp = buffer; *cp; cp++)
+       ;
+    if (offset >= 100) {
+       *cp++ = '0' + offset / 100;
+       offset %= 100;
+       started++;
+    }
+    if (started || offset >= 10) {
+       *cp++ = '0' + offset / 10;
+       offset %= 10;
+    }
+    *cp++ = '0' + offset;
+    *cp = '\0';
+    return(buffer);
+}
diff --git a/lib/et/error_table.h b/lib/et/error_table.h
new file mode 100644 (file)
index 0000000..78f7db2
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1988 by the Student Information Processing Board of the
+ * Massachusetts Institute of Technology.
+ *
+ * For copyright info, see mit-sipb-copyright.h.
+ */
+
+#ifndef _ET_H
+/* Are we using ANSI C? */
+#ifndef __STDC__
+#define const
+#endif
+extern int errno;
+struct error_table {
+    char const * const * msgs;
+    long base;
+    int n_msgs;
+};
+struct et_list {
+    struct et_list *next;
+    const struct error_table *table;
+};
+extern struct et_list * _et_list;
+
+#define        ERRCODE_RANGE   8       /* # of bits to shift table number */
+#define        BITS_PER_CHAR   6       /* # bits to shift per character in name */
+
+extern const char *error_table_name();
+#define _ET_H
+#endif
diff --git a/lib/et/et_c.awk b/lib/et/et_c.awk
new file mode 100644 (file)
index 0000000..e3d4c91
--- /dev/null
@@ -0,0 +1,185 @@
+BEGIN { 
+char_shift=64
+## "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+c2n["A"]=1
+c2n["B"]=2
+c2n["C"]=3
+c2n["D"]=4
+c2n["E"]=5
+c2n["F"]=6
+c2n["G"]=7
+c2n["H"]=8
+c2n["I"]=9
+c2n["J"]=10
+c2n["K"]=11
+c2n["L"]=12
+c2n["M"]=13
+c2n["N"]=14
+c2n["O"]=15
+c2n["P"]=16
+c2n["Q"]=17
+c2n["R"]=18
+c2n["S"]=19
+c2n["T"]=20
+c2n["U"]=21
+c2n["V"]=22
+c2n["W"]=23
+c2n["X"]=24
+c2n["Y"]=25
+c2n["Z"]=26
+c2n["a"]=27
+c2n["b"]=28
+c2n["c"]=29
+c2n["d"]=30
+c2n["e"]=31
+c2n["f"]=32
+c2n["g"]=33
+c2n["h"]=34
+c2n["i"]=35
+c2n["j"]=36
+c2n["k"]=37
+c2n["l"]=38
+c2n["m"]=39
+c2n["n"]=40
+c2n["o"]=41
+c2n["p"]=42
+c2n["q"]=43
+c2n["r"]=44
+c2n["s"]=45
+c2n["t"]=46
+c2n["u"]=47
+c2n["v"]=48
+c2n["w"]=49
+c2n["x"]=50
+c2n["y"]=51
+c2n["z"]=52
+c2n["0"]=53
+c2n["1"]=54
+c2n["2"]=55
+c2n["3"]=56
+c2n["4"]=57
+c2n["5"]=58
+c2n["6"]=59
+c2n["7"]=60
+c2n["8"]=61
+c2n["9"]=62
+c2n["_"]=63
+}
+/^#/ { next }
+/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/ {
+       table_number = 0
+       table_name = $2
+       mod_base = 1000000
+       for(i=1; i<=length(table_name); i++) {
+           table_number=(table_number*char_shift)+c2n[substr(table_name,i,1)]
+       }
+
+       # We start playing *_high, *low games here because the some
+       # awk programs do not have the necessary precision (sigh)
+       tab_base_low = table_number % mod_base
+       tab_base_high = int(table_number / mod_base)
+       tab_base_sign = 1;
+
+       # figure out: table_number_base=table_number*256
+       tab_base_low = tab_base_low * 256
+       tab_base_high = (tab_base_high * 256) + \
+                       int(tab_base_low / mod_base)
+       tab_base_low = tab_base_low % mod_base
+
+       if (table_number > 128*256*256) {
+               # figure out:  table_number_base -= 256*256*256*256
+               # sub_high, sub_low is 256*256*256*256
+               sub_low = 256*256*256 % mod_base
+               sub_high = int(256*256*256 / mod_base)
+
+               sub_low = sub_low * 256
+               sub_high = (sub_high * 256) + int(sub_low / mod_base)
+               sub_low = sub_low % mod_base
+
+               tab_base_low = sub_low - tab_base_low;
+               tab_base_high = sub_high - tab_base_high;
+               tab_base_sign = -1;
+               if (tab_base_low < 0) {
+                       tab_base_low = tab_base_low + mod_base
+                       tab_base_high--
+               }
+       }
+       print "/*" > outfile
+       print " * " outfile ":" > outfile
+       print " * This file is automatically generated; please do not edit it." > outfile
+       print " */" > outfile
+
+       print "#ifdef __STDC__" > outfile
+       print "#define NOARGS void" > outfile
+       print "#else" > outfile
+       print "#define NOARGS" > outfile
+       print "#define const" > outfile
+       print "#endif" > outfile
+       print "" > outfile
+       print "static const char * const text[] = {" > outfile
+       table_item_count = 0
+}
+
+/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*$/ {
+       skipone=1
+       next
+}
+
+/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*".*"[ \t]*$/ {
+       text=""
+       for (i=3; i<=NF; i++) { 
+           text = text FS $i
+       }
+       text=substr(text,2,length(text)-1);
+       printf "\t%s,\n", text > outfile
+       table_item_count++
+}
+
+{ 
+       if (skipone) {
+           printf "\t%s,\n", $0 > outfile
+           table_item_count++
+       }
+       skipone=0
+}
+END {
+
+
+       print "    0" > outfile
+       print "};" > outfile
+       print "" > outfile
+       print "struct error_table {" > outfile
+       print "    char const * const * msgs;" > outfile
+       print "    long base;" > outfile
+       print "    int n_msgs;" > outfile
+       print "};" > outfile
+       print "struct et_list {" > outfile
+       print "    struct et_list *next;" > outfile
+       print "    const struct error_table * table;" > outfile
+       print "};" > outfile
+       print "extern struct et_list *_et_list;" > outfile
+       print "" > outfile
+       if (tab_base_high == 0) {
+           print "static const struct error_table et = { text, " \
+               sprintf("%dL, %d };", tab_base_sign*tab_base_low, \
+               table_item_count) > outfile
+       } else {
+           print "static const struct error_table et = { text, " \
+               sprintf("%d%06dL, %d };", tab_base_sign*tab_base_high, \
+               tab_base_low, table_item_count) > outfile
+       }
+       print "" > outfile
+       print "static struct et_list link = { 0, 0 };" > outfile
+       print "" > outfile
+       print "void initialize_" table_name "_error_table (NOARGS);" > outfile
+       print "" > outfile
+       print "void initialize_" table_name "_error_table (NOARGS) {" > outfile
+       print "    if (!link.table) {" > outfile
+       print "        link.next = _et_list;" > outfile
+       print "        link.table = &et;" > outfile
+       print "        _et_list = &link;" > outfile
+       print "    }" > outfile
+       print "}" > outfile
+       
+
+}
diff --git a/lib/et/et_h.awk b/lib/et/et_h.awk
new file mode 100644 (file)
index 0000000..d7688e9
--- /dev/null
@@ -0,0 +1,157 @@
+BEGIN { 
+char_shift=64
+## "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+c2n["A"]=1
+c2n["B"]=2
+c2n["C"]=3
+c2n["D"]=4
+c2n["E"]=5
+c2n["F"]=6
+c2n["G"]=7
+c2n["H"]=8
+c2n["I"]=9
+c2n["J"]=10
+c2n["K"]=11
+c2n["L"]=12
+c2n["M"]=13
+c2n["N"]=14
+c2n["O"]=15
+c2n["P"]=16
+c2n["Q"]=17
+c2n["R"]=18
+c2n["S"]=19
+c2n["T"]=20
+c2n["U"]=21
+c2n["V"]=22
+c2n["W"]=23
+c2n["X"]=24
+c2n["Y"]=25
+c2n["Z"]=26
+c2n["a"]=27
+c2n["b"]=28
+c2n["c"]=29
+c2n["d"]=30
+c2n["e"]=31
+c2n["f"]=32
+c2n["g"]=33
+c2n["h"]=34
+c2n["i"]=35
+c2n["j"]=36
+c2n["k"]=37
+c2n["l"]=38
+c2n["m"]=39
+c2n["n"]=40
+c2n["o"]=41
+c2n["p"]=42
+c2n["q"]=43
+c2n["r"]=44
+c2n["s"]=45
+c2n["t"]=46
+c2n["u"]=47
+c2n["v"]=48
+c2n["w"]=49
+c2n["x"]=50
+c2n["y"]=51
+c2n["z"]=52
+c2n["0"]=53
+c2n["1"]=54
+c2n["2"]=55
+c2n["3"]=56
+c2n["4"]=57
+c2n["5"]=58
+c2n["6"]=59
+c2n["7"]=60
+c2n["8"]=61
+c2n["9"]=62
+c2n["_"]=63
+}
+/^#/ { next }
+/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/ {
+       table_number = 0
+       table_name = $2
+       mod_base = 1000000
+       for(i=1; i<=length(table_name); i++) {
+           table_number=(table_number*char_shift)+c2n[substr(table_name,i,1)]
+       }
+       # We start playing *_high, *low games here because the some
+       # awk programs do not have the necessary precision (sigh)
+       tab_base_low = table_number % mod_base
+       tab_base_high = int(table_number / mod_base)
+       tab_base_sign = 1;
+
+       # figure out: table_number_base=table_number*256
+       tab_base_low = tab_base_low * 256
+       tab_base_high = (tab_base_high * 256) + \
+                       int(tab_base_low / mod_base)
+       tab_base_low = tab_base_low % mod_base
+
+       if (table_number > 128*256*256) {
+               # figure out:  table_number_base -= 256*256*256*256
+               # sub_high, sub_low is 256*256*256*256
+               sub_low = 256*256*256 % mod_base
+               sub_high = int(256*256*256 / mod_base)
+
+               sub_low = sub_low * 256
+               sub_high = (sub_high * 256) + int(sub_low / mod_base)
+               sub_low = sub_low % mod_base
+
+               tab_base_low = sub_low - tab_base_low;
+               tab_base_high = sub_high - tab_base_high;
+               tab_base_sign = -1;
+               if (tab_base_low < 0) {
+                       tab_base_low = tab_base_low + mod_base
+                       tab_base_high--
+               }
+       }
+       curr_low = tab_base_low
+       curr_high = tab_base_high
+       curr_sign = tab_base_sign
+       print "/*" > outfile
+       print " * " outfile ":" > outfile
+       print " * This file is automatically generated; please do not edit it." > outfile
+       print " */" > outfile
+       print "#ifdef __STDC__" > outfile
+       print "#define NOARGS void" > outfile
+       print "#else" > outfile
+       print "#define NOARGS" > outfile
+       print "#define const" > outfile
+       print "#endif" > outfile
+       print "" > outfile
+}
+
+/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,/ {
+       tag=substr($2,1,length($2)-1)
+       if (curr_high == 0) {
+               printf "#define %-40s (%dL)\n", tag, \
+                       curr_sign*curr_low > outfile
+       } else {
+               printf "#define %-40s (%d%06dL)\n", tag, curr_high*curr_sign, \
+                       curr_low > outfile
+       }
+       curr_low += curr_sign;
+       if (curr_low >= mod_base) {
+               curr_low -= mod_base;
+               curr_high++
+       }
+       if (curr_low < 0) {
+               cur_low += mod_base
+               cur_high--
+       }
+}
+
+END {
+       print "extern void initialize_" table_name "_error_table (NOARGS);" > outfile
+       if (tab_base_high == 0) {
+               print "#define ERROR_TABLE_BASE_" table_name " (" \
+                       sprintf("%d", tab_base_sign*tab_base_low) \
+                       "L)" > outfile
+       } else {
+               print "#define ERROR_TABLE_BASE_" table_name " (" \
+                       sprintf("%d%06d", tab_base_sign*tab_base_high, \
+                       tab_base_low) "L)" > outfile
+       }
+       print "" > outfile
+       print "/* for compatibility with older versions... */" > outfile
+       print "#define init_" table_name "_err_tbl initialize_" table_name "_error_table" > outfile
+       print "#define " table_name "_err_base ERROR_TABLE_BASE_" table_name > outfile
+}
diff --git a/lib/et/et_name.c b/lib/et/et_name.c
new file mode 100644 (file)
index 0000000..19da71d
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1987 by MIT Student Information Processing Board
+ *
+ * For copyright info, see mit-sipb-copyright.h.
+ */
+
+#include "error_table.h"
+#include "mit-sipb-copyright.h"
+#include "internal.h"
+
+#ifndef        lint
+static const char copyright[] =
+    "Copyright 1987,1988 by Student Information Processing Board, Massachusetts Institute of Technology";
+static const char rcsid_et_name_c[] =
+    "$Header$";
+#endif
+
+static const char char_set[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+
+static char buf[6];
+
+const char * error_table_name(num)
+    int num;
+{
+    int ch;
+    int i;
+    char *p;
+
+    /* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */
+    p = buf;
+    num >>= ERRCODE_RANGE;
+    /* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */
+    num &= 077777777;
+    /* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */
+    for (i = 4; i >= 0; i--) {
+       ch = (num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1);
+       if (ch != 0)
+           *p++ = char_set[ch-1];
+    }
+    *p = '\0';
+    return(buf);
+}
diff --git a/lib/et/init_et.c b/lib/et/init_et.c
new file mode 100644 (file)
index 0000000..856f0fd
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * $Header$
+ * $Source$
+ * $Locker$
+ *
+ * Copyright 1986, 1987, 1988 by MIT Information Systems and
+ *     the MIT Student Information Processing Board.
+ *
+ * For copyright info, see mit-sipb-copyright.h.
+ */
+
+#include <stdio.h>
+#include "error_table.h"
+#include "mit-sipb-copyright.h"
+
+#ifndef __STDC__
+#define const
+#endif
+
+#ifndef        lint
+static const char rcsid_init_et_c[] =
+    "$Header$";
+#endif
+
+extern char *malloc(), *realloc();
+
+struct foobar {
+    struct et_list etl;
+    struct error_table et;
+};
+
+extern struct et_list * _et_list;
+
+int init_error_table(msgs, base, count)
+    const char * const * msgs;
+    int base;
+    int count;
+{
+    struct foobar * new_et;
+
+    if (!base || !count || !msgs)
+       return 0;
+
+    new_et = (struct foobar *) malloc(sizeof(struct foobar));
+    if (!new_et)
+       return errno;   /* oops */
+    new_et->etl.table = &new_et->et;
+    new_et->et.msgs = msgs;
+    new_et->et.base = base;
+    new_et->et.n_msgs= count;
+
+    new_et->etl.next = _et_list;
+    _et_list = &new_et->etl;
+    return 0;
+}
diff --git a/lib/et/internal.h b/lib/et/internal.h
new file mode 100644 (file)
index 0000000..112c016
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * internal include file for com_err package
+ */
+#include "mit-sipb-copyright.h"
+#ifndef __STDC__
+#undef const
+#define const
+#endif
+
+#include <errno.h>
+
+#ifdef NEED_SYS_ERRLIST
+extern char const * const sys_errlist[];
+extern const int sys_nerr;
+#endif
+
+/* AIX and Ultrix have standard conforming header files. */
+#if !defined(ultrix) && !defined(_AIX)
+#ifdef __STDC__
+void perror (const char *);
+#endif
+#endif
diff --git a/lib/et/mit-sipb-copyright.h b/lib/et/mit-sipb-copyright.h
new file mode 100644 (file)
index 0000000..2f7eb29
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+
+Copyright 1987, 1988 by the Student Information Processing Board
+       of the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is
+hereby granted, provided that the above copyright notice
+appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation,
+and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+M.I.T. and the M.I.T. S.I.P.B. make no representations about
+the suitability of this software for any purpose.  It is
+provided "as is" without express or implied warranty.
+
+*/
+
diff --git a/lib/et/texinfo.tex b/lib/et/texinfo.tex
new file mode 100644 (file)
index 0000000..838160c
--- /dev/null
@@ -0,0 +1,2077 @@
+%% TeX macros to handle texinfo files
+
+%   Copyright (C) 1985, 1986, 1988 Richard M. Stallman
+
+%                     NO WARRANTY
+
+%  BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
+%NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
+%WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
+%RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
+%WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+%BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+%FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
+%AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
+%DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+%CORRECTION.
+
+% IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
+%STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
+%WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
+%LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
+%OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+%USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
+%DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
+%A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
+%PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
+%DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
+
+%              GENERAL PUBLIC LICENSE TO COPY
+
+%  1. You may copy and distribute verbatim copies of this source file
+%as you receive it, in any medium, provided that you conspicuously
+%and appropriately publish on each copy a valid copyright notice
+%"Copyright (C) 1986 Richard M. Stallman"; and include
+%following the copyright notice a verbatim copy of the above disclaimer
+%of warranty and of this License.
+
+%  2. You may modify your copy or copies of this source file or
+%any portion of it, and copy and distribute such modifications under
+%the terms of Paragraph 1 above, provided that you also do the following:
+
+%    a) cause the modified files to carry prominent notices stating
+%    that you changed the files and the date of any change; and
+
+%    b) cause the whole of any work that you distribute or publish,
+%    that in whole or in part contains or is a derivative of this
+%    program or any part thereof, to be licensed at no charge to all
+%    third parties on terms identical to those contained in this
+%    License Agreement (except that you may choose to grant more extensive
+%    warranty protection to some or all third parties, at your option).
+
+%    c) You may charge a distribution fee for the physical act of
+%    transferring a copy, and you may at your option offer warranty
+%    protection in exchange for a fee.
+
+%Mere aggregation of another unrelated program with this program (or its
+%derivative) on a volume of a storage or distribution medium does not bring
+%the other program under the scope of these terms.
+
+%  3. You may copy and distribute this program (or a portion or derivative
+%of it, under Paragraph 2) in object code or executable form under the terms
+%of Paragraphs 1 and 2 above provided that you also do one of the following:
+
+%    a) accompany it with the complete corresponding machine-readable
+%    source code, which must be distributed under the terms of
+%    Paragraphs 1 and 2 above; or,
+
+%    b) accompany it with a written offer, valid for at least three
+%    years, to give any third party free (except for a nominal
+%    shipping charge) a complete machine-readable copy of the
+%    corresponding source code, to be distributed under the terms of
+%    Paragraphs 1 and 2 above; or,
+
+%    c) accompany it with the information you received as to where the
+%    corresponding source code may be obtained.  (This alternative is
+%    allowed only for noncommercial distribution and only if you
+%    received the program in object code or executable form alone.)
+
+%For an executable file, complete source code means all the source code for
+%all modules it contains; but, as a special exception, it need not include
+%source code for modules which are standard libraries that accompany the
+%operating system on which the executable file runs.
+
+%  4. You may not copy, sublicense, distribute or transfer this program
+%except as expressly provided under this License Agreement.  Any attempt
+%otherwise to copy, sublicense, distribute or transfer this program is void and
+%your rights to use the program under this License agreement shall be
+%automatically terminated.  However, parties who have received computer
+%software programs from you with this License Agreement will not have
+%their licenses terminated so long as such parties remain in full compliance.
+
+%  5. If you wish to incorporate parts of this program into other free
+%programs whose distribution conditions are different, write to the Free
+%Software Foundation at 675 Mass Ave, Cambridge, MA 02139.  We have not yet
+%worked out a simple rule that can be stated here, but we will often permit
+%this.  We will be guided by the two goals of preserving the free status of
+%all derivatives of our free software and of promoting the sharing and reuse of
+%software.
+
+%In other words, you are welcome to use, share and improve this program.
+%You are forbidden to forbid anyone else to use, share and improve
+%what you give them.   Help stamp out software-hoarding!
+
+\def\texinfoversion{1.18}
+\message{Loading texinfo package [Version \texinfoversion]:}
+\message{}
+
+% Save some parts of plain tex whose names we will redefine.
+
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexdot=\.
+\let\ptexstar=\*
+\let\ptexend=\end
+\let\ptexbullet=\bullet
+\let\ptexb=\b
+\let\ptexc=\c
+\let\ptexi=\i
+\let\ptext=\t
+\let\ptexl=\l
+\let\ptexL=\L
+
+\def\tie{\penalty 10000\ }     % Save plain tex definition of ~.
+
+\message{Basics,}
+\chardef\other=12
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset  \bindingoffset=0pt
+\newdimen \normaloffset   \normaloffset=\hoffset
+\newdimen\pagewidth \newdimen\pageheight
+\pagewidth=\hsize \pageheight=\vsize
+
+%---------------------Begin change-----------------------
+%
+% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\cornerlong \newdimen\cornerthick
+\newdimen \topandbottommargin
+\newdimen \outerhsize \newdimen \outervsize
+\cornerlong=1pc\cornerthick=.3pt       % These set size of cropmarks
+\outerhsize=7in
+\outervsize=9.5in
+\topandbottommargin=.75in
+%
+%---------------------End change-----------------------
+
+% \onepageout takes a vbox as an argument.  Note that \pagecontents
+% does insertions itself, but you have to call it yourself.
+\chardef\PAGE=255  \output={\onepageout{\pagecontents\PAGE}}
+\def\onepageout#1{\hoffset=\normaloffset
+\ifodd\pageno  \advance\hoffset by \bindingoffset
+\else \advance\hoffset by -\bindingoffset\fi
+\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}%
+ {\let\hsize=\pagewidth \makefootline}}
+\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+
+
+% Here is a modification of the main output routine for Near East Publications
+% This provides right-angle cropmarks at all four corners.
+% The contents of the page are centerlined into the cropmarks,
+% and any desired binding offset is added as an \hskip on either
+% site of the centerlined box.  (P. A. MacKay, 12 November, 1986)
+%
+\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up
+                \shipout
+                \vbox to \outervsize{\hsize=\outerhsize
+                 \vbox{\line{\ewtop\hfill\ewtop}}
+                 \nointerlineskip
+                 \line{\vbox{\moveleft\cornerthick\nstop}
+                       \hfill
+                       \vbox{\moveright\cornerthick\nstop}}
+                 \vskip \topandbottommargin
+                 \centerline{\ifodd\pageno\hskip\bindingoffset\fi
+                       \vbox{
+                       {\let\hsize=\pagewidth \makeheadline}
+                       \pagebody{#1}
+                       {\let\hsize=\pagewidth \makefootline}}
+                       \ifodd\pageno\else\hskip\bindingoffset\fi}
+                \vskip \topandbottommargin plus1fill minus1fill
+                 \boxmaxdepth\cornerthick
+                 \line{\vbox{\moveleft\cornerthick\nsbot}
+                       \hfill
+                       \vbox{\moveright\cornerthick\nsbot}}
+                 \nointerlineskip
+                 \vbox{\line{\ewbot\hfill\ewbot}}
+       }
+  \advancepageno 
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+%
+% Do @cropmarks to get crop marks
+\def\cropmarks{\let\onepageout=\croppageout }
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+%
+% Here are the rules for the cropmarks.  Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+  {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+  {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1.
+% The argument can be delimited with [...] or with "..." or braces
+% or it can be a whole line.
+% #1 should be a macro which expects
+% an ordinary undelimited TeX argument.
+
+\def\parsearg #1{\let\next=#1\begingroup\obeylines\futurelet\temp\parseargx}
+
+\def\parseargx{%
+\ifx \obeyedspace\temp \aftergroup\parseargdiscardspace \else%
+\aftergroup \parseargline %
+\fi \endgroup}
+
+{\obeyspaces %
+\gdef\parseargdiscardspace {\begingroup\obeylines\futurelet\temp\parseargx}}
+
+\gdef\obeyedspace{\ }
+
+\def\parseargline{\begingroup \obeylines \parsearglinex}
+{\obeylines %
+\gdef\parsearglinex #1^^M{\endgroup \next {#1}}}
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment.  Type Return to continue.}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo  is the same as @foo, for now.
+\newhelp\EMsimple{Type <Return> to continue}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+%% @end foo executes the definition of \Efoo.
+%% foo can be delimited by doublequotes or brackets.
+
+\def\end{\parsearg\endxxx}
+
+\def\endxxx #1{%
+\expandafter\ifx\csname E#1\endcsname\relax
+\expandafter\ifx\csname #1\endcsname\relax
+\errmessage{Undefined command @end #1}\else
+\errorE{#1}\fi\fi
+\csname E#1\endcsname}
+\def\errorE#1{
+{\errhelp=\EMsimple \errmessage{@end #1 not within #1 environment}}}
+
+% Single-spacing is done by various environments.
+
+\newskip\singlespaceskip \singlespaceskip = \baselineskip
+\def\singlespace{%
+{\advance \baselineskip by -\singlespaceskip
+\kern \baselineskip}%
+\baselineskip=\singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\sf \char '100}}
+
+% Define @` and @' to be the same as ` and '
+% but suppressing ligatures.
+\def\`{{`}}
+\def\'{{'}}
+
+% Used to generate quoted braces.
+
+\def\mylbrace {{\tt \char '173}}
+\def\myrbrace {{\tt \char '175}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break}
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @w prevents a word break
+\def\w #1{\hbox{#1}}
+
+% @group ... @end group  forces ... to be all on one page.
+
+\def\group{\begingroup% \inENV ???
+\def \Egroup{\egroup\endgroup}
+\vbox\bgroup}
+
+% @br   forces paragraph break
+
+\let\br = \par
+
+% @dots{}  output some dots
+
+\def\dots{$\ldots$}
+
+% @page    forces the start of a new page
+
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+\def\exdent{\errmessage{@exdent in filled text}}
+  % @lisp, etc, define \exdent locally from \internalexdent
+
+{\obeyspaces
+\gdef\internalexdent{\parsearg\exdentzzz}}
+
+\def\exdentzzz #1{{\advance \leftskip by -\lispnarrowing
+\advance \hsize by -\leftskip
+\advance \hsize by -\rightskip
+\leftline{{\rm#1}}}}
+
+% @include file    insert text of that file as input.
+
+\def\include{\parsearg\includezzz}
+\def\includezzz #1{{\def\thisfile{#1}\input #1
+}}
+
+\def\thisfile{}
+
+% @center line   outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n   outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\par \vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore  is another way to write a comment
+
+\def\comment{\parsearg \commentxxx}
+
+\def\commentxxx #1{}
+
+\let\c=\comment
+
+\long\def\ignore #1\end ignore{}
+
+\outer\def\ifset{\parsearg\ifsetxxx}
+
+\def\ifsetxxx #1#2\end ifset{%
+\expandafter\ifx\csname IF#1\endcsname\relax \else #2\fi}
+
+\outer\def\ifclear{\parsearg\ifclearxxx}
+
+\def\ifclearxxx #1#2\end ifclear{%
+\expandafter\ifx\csname IF#1\endcsname\relax #2\fi}
+
+% Some texinfo constructs that are trivial in tex
+
+\def\iftex{}
+\def\Eiftex{}
+\long\def\ifinfo #1\end ifinfo{}
+\long\def\menu #1\end menu{}
+\def\asis#1{#1}
+
+\def\node{\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\lastnode=\relax
+
+\def\donoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\setref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\def\unnumbnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\let\refill=\relax
+
+\let\setfilename=\comment
+
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\losespace#3{}}, node `\losespace#1{}'}
+\def\losespace #1{#1}
+
+\message{fonts,}
+
+% Font-change commands.
+
+%% Try out Computer Modern fonts at \magstephalf
+\font\tenrm=cmr10 scaled \magstephalf
+\font\tentt=cmtt10 scaled \magstephalf
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\font\tenbf=cmb10 scaled \magstephalf 
+\font\tenit=cmti10 scaled \magstephalf
+\font\tensl=cmsl10 scaled \magstephalf
+\font\tensf=cmss10 scaled \magstephalf
+\def\li{\sf}
+\font\tensc=cmcsc10 scaled \magstephalf
+
+% Fonts for @defun, etc.
+\font\defbf=cmbx10 scaled \magstep1 %was 1314
+\let\deftt=\tentt
+\def\df{\let\tt=\deftt \defbf}
+
+% Font for title
+\font\titlerm = cmbx10 scaled \magstep5
+
+% Fonts for indices
+\font\indit=cmti9 \font\indrm=cmr9
+\def\indbf{\indrm} \def\indsl{\indit}
+\def\indexfonts{\let\it=\indit \let\sl=\indsl \let\bf=\indbf \let\rm=\indrm}
+
+% Fonts for headings
+\font\chaprm=cmbx10 scaled \magstep3
+\font\chapit=cmti10 scaled \magstep3
+\font\chapsl=cmsl10 scaled \magstep3
+\font\chaptt=cmtt10 scaled \magstep3
+\font\chapsf=cmss10 scaled \magstep3
+\let\chapbf=\chaprm
+
+\font\secrm=cmbx10 scaled \magstep2
+\font\secit=cmti10 scaled \magstep2
+\font\secsl=cmsl10 scaled \magstep2
+\font\sectt=cmtt10 scaled \magstep2
+\font\secsf=cmss10 scaled \magstep2
+\let\secbf=\secrm
+
+\font\ssecrm=cmbx10 scaled \magstep1
+\font\ssecit=cmti10 scaled \magstep1
+\font\ssecsl=cmsl10 scaled \magstep1
+\font\ssectt=cmtt10 scaled \magstep1
+\font\ssecsf=cmss10 scaled \magstep1
+\let\ssecbf=\ssecrm
+
+\def\textfonts{\let\rm=\tenrm\let\it=\tenit\let\sl=\tensl\let\bf=\tenbf%
+\let\sc=\tensc\let\sf=\tensf}
+\def\chapfonts{\let\rm=\chaprm\let\it=\chapit\let\sl=\chapsl\let\bf=\chapbf\let\tt=\chaptt\let\sf=\chapsf}
+\def\secfonts{\let\rm=\secrm\let\it=\secit\let\sl=\secsl\let\bf=\secbf\let\tt=\sectt\let\sf=\secsf}
+\def\subsecfonts{\let\rm=\ssecrm\let\it=\ssecit\let\sl=\ssecsl\let\bf=\ssecbf\let\tt=\ssectt\let\sf=\ssecsf}
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+\def\i#1{{\sl #1}}
+\let\var=\i
+\let\dfn=\i
+\let\emph=\i
+\let\cite=\i
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+\def\t#1{{\tt \rawbackslash \frenchspacing #1}\null}
+\let\ttfont = \t
+\let\kbd=\t
+\let\code=\t
+\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null}
+\def\key #1{{\tt \uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+\let\file=\samp
+
+\def\l#1{{\li #1}\null}
+
+\def\r#1{{\rm #1}}
+\def\s#1{{\sc #1}}
+\def\ii#1{{\it #1}}
+
+\def\titlefont#1{{\titlerm #1}}
+
+\def\titlepage{\begingroup \parindent=0pt \hbox{}%
+\let\oldpage=\page
+\def\page{\oldpage \hbox{}}}
+
+\def\Etitlepage{\endgroup\page\HEADINGSon}
+
+% Make altmode in file print out right
+
+\catcode `\^^[=\active \def^^[{$\diamondsuit$}
+
+\message{page headings,}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks \evenheadline    % Token sequence for heading line of even pages
+\newtoks \oddheadline     % Token sequence for heading line of odd pages
+\newtoks \evenfootline    % Token sequence for footing line of even pages
+\newtoks \oddfootline     % Token sequence for footing line of odd pages
+
+% Now make Tex use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline \else \the\evenfootline \fi}}
+
+% Commands to set those variables.
+% For example, this is what  @headings on  does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish}
+\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish}
+\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+%
+}% unbind the catcode of @.
+
+% @headings on   turns them on.
+% @headings off  turns them off.
+% By default, they are off.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1,
+% Put current file name in lower left corner,
+% Put chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSon{
+\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{\number\day\space
+\ifcase\month\or
+January\or February\or March\or April\or May\or June\or
+July\or August\or September\or October\or November\or December\fi
+\space\number\year}
+
+% Use this if you want the Month Day, Year style of output.
+%\def\today{\ifcase\month\or
+%January\or February\or March\or April\or May\or June\or
+%July\or August\or September\or October\or November\or December\fi
+%\space\number\day, \number\year}
+
+% @settitle line...  specifies the title of the document, for headings
+% It generates no output of its own
+
+\def\thistitle{No Title}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+\message{tables,}
+
+% Tables -- @table, @ftable, @item(x), @kitem(x), @xitem(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent  \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin  \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table and @ftable define @item, @itemx, etc., with these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\par \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \par \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\par \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}\itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}\itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+\advance \hsize by -\rightskip %
+\advance \hsize by -\leftskip %
+\setbox0=\hbox{\itemfont{#1}}%
+\itemindex{#1}%
+\parskip=0in %
+\noindent %
+\ifdim \wd0>\itemmax %
+\vadjust{\penalty 10000}%
+\hbox to \hsize{\hskip -\tableindent\box0\hss}\ %
+\else %
+\hbox to 0pt{\hskip -\tableindent\box0\hss}%
+\fi %
+\endgroup %
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+%% Contains a kludge to get @end[description] to work
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1        \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1        \endtabley}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Neccessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\endgroup\afterenvbreak}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{\itemizey {#1}{\Eitemize}}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\begingroup %
+\itemno = 0 %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\endgroup\afterenvbreak}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+\def\bullet{$\ptexbullet$}
+\def\minus{$-$}
+
+\def\enumerate{\itemizey{\the\itemno.}\Eenumerate\flushcr}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{\in hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 300}}%
+\flushcr}
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that        accumulates this index.  The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+
+\def\newindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1        % Open the file
+\expandafter\xdef\csname#1index\endcsname{%    % Define \xxxindex
+\noexpand\doindex {#1}}
+}
+
+% @defindex foo  ==  \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1        % Open the file
+\expandafter\xdef\csname#1index\endcsname{%    % Define \xxxindex
+\noexpand\docodeindex {#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar    makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+\def\synindex #1 #2 {%
+\expandafter\xdef\csname#1index\endcsname{%    % Define \xxxindex
+\noexpand\doindex {#2}}%
+}
+
+% @syncodeindex foo bar   similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex #1 #2 {%
+\expandafter\xdef\csname#1index\endcsname{%    % Define \xxxindex
+\noexpand\docodeindex {#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+%  and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+\def\bf{\realbackslash bf }%
+\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\dots{\realbackslash dots }%
+\def\copyright{\realbackslash copyright }%
+}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexnofonts{%
+\let\code=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+@gdef@realbackslash{\}}
+
+\let\indexbackslash=0  %overridden during \printindex.
+
+\def\doind #1#2{%
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\count10=\lastpenalty %
+\escapechar=`\\%
+{\let\folio=0% Expand all macros now EXCEPT \folio
+\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+% so it will be output as is; and it will print as backslash in the indx.
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2}%
+}%
+% Now produce the complete index entry.  We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}}}%
+\temp }%
+\penalty\count10}}
+
+\def\dosubind #1#2#3{%
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\count10=\lastpenalty %
+\escapechar=`\\%
+{\let\folio=0%
+\def\rawbackslashxx{\indexbackslash}%
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2 #3}%
+}%
+% Now produce the complete index entry.  We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}{#3}}}%
+\temp }%
+\penalty\count10}}
+
+% The index entry written in the file actually looks like
+%  \entry {sortstring}{page}{topic}
+% or
+%  \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+%  \initial {c}
+%     before the first topic whose initial is c
+%  \entry {topic}{pagelist}
+%     for a topic that is used without subtopics
+%  \primary {topic}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+
+% Define the user-accessible indexing commands 
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% This is what you call to cause a particular index to get printed.
+% Write
+% @unnumbered Function Index
+% @printindex fn
+
+\def\printindex{\parsearg\doprintindex}
+
+\def\doprintindex#1{\tex %
+\catcode`\%=\other\catcode`\&=\other\catcode`\#=\other
+\catcode`\$=\other\catcode`\_=\other
+\catcode`\~=\other
+\def\indexbackslash{\rawbackslashxx}
+\indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt
+\begindoublecolumns
+\openin 1 \jobname.#1s
+\ifeof 1 \else \closein 1 \input \jobname.#1s
+\fi
+\enddoublecolumns
+\Etex}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+% Same as \bigskipamount except no shrink.
+% \balancecolumns gets confused if there is any shrink.
+\newskip\initialskipamount \initialskipamount 12pt plus4pt
+
+\outer\def\initial #1{%
+{\let\tentt=\sectt \let\sf=\sectt
+\ifdim\lastskip<\initialskipamount
+\removelastskip \penalty-200 \vskip \initialskipamount\fi
+\line{\secbf#1\hfill}\kern 2pt\penalty3000}}
+
+\outer\def\entry #1#2{
+{\parfillskip=0in \parskip=0in \parindent=0in
+\hangindent=1in \hangafter=1%
+\noindent\hbox{#1}\leaders\Dotsbox\hskip 0pt plus 1filll #2\par
+}}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\leaders\Dotsbox\hskip 0pt plus 1filll#2\par
+}}
+
+%% Define two-column mode, which is used in indexes.
+%% Adapted from the TeXBook, page 416
+\catcode `\@=11
+
+\newbox\partialpage
+
+\newdimen\doublecolumnhsize  \doublecolumnhsize = 3.11in
+\newdimen\doublecolumnvsize  \doublecolumnvsize = 19.1in
+
+\def\begindoublecolumns{\begingroup
+  \output={\global\setbox\partialpage=\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}\eject
+  \output={\doublecolumnout} \hsize=\doublecolumnhsize \vsize=\doublecolumnvsize}
+\def\enddoublecolumns{\output={\balancecolumns}\eject
+  \endgroup \pagegoal=\vsize}
+
+\def\doublecolumnout{\splittopskip=\topskip \splitmaxdepth=\maxdepth
+  \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage
+  \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+  \onepageout\pagesofar \unvbox255 \penalty\outputpenalty}
+\def\pagesofar{\unvbox\partialpage %
+  \hsize=\doublecolumnhsize % have to restore this since output routine
+%            changes it to set cropmarks (P. A. MacKay, 12 Nov. 1986)
+  \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}}
+\def\balancecolumns{\setbox0=\vbox{\unvbox255} \dimen@=\ht0
+  \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
+  \divide\dimen@ by2 \splittopskip=\topskip
+  {\vbadness=10000 \loop \global\setbox3=\copy0
+    \global\setbox1=\vsplit3 to\dimen@
+    \ifdim\ht3>\dimen@ \global\advance\dimen@ by1pt \repeat}
+  \setbox0=\vbox to\dimen@{\unvbox1}  \setbox2=\vbox to\dimen@{\unvbox3}
+  \pagesofar}
+
+\catcode `\@=\other
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\newcount \chapno
+\newcount \secno
+\newcount \subsecno
+\newcount \subsubsecno
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount \appendixno  \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+\newwrite \contentsfile
+\openout \contentsfile = \jobname.toc
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it.  @section does likewise
+
+\def\thischapter{} \def\thissection{}
+\def\seccheck#1{\if \pageno<0 %
+\errmessage{@#1 not allowed after generating table of contents}\fi
+%
+}
+
+\outer\def\chapter{\parsearg\chapterzzz}
+\def\chapterzzz #1{\seccheck{chapter}%
+\secno=0 \subsecno=0 \subsubsecno=0 \global\advance \chapno by 1 \message{Chapter \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}\gdef\thischapter{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\donoderef %
+}
+
+\outer\def\appendix{\parsearg\appendixzzz}
+\def\appendixzzz #1{\seccheck{appendix}%
+\secno=0 \subsecno=0 \subsubsecno=0 \global\advance \appendixno by 1 \message{Appendix \appendixletter}%
+\chapmacro {#1}{Appendix \appendixletter}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash chapentry {#1}{Appendix \appendixletter}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\unnumbnoderef %
+}
+
+\outer\def\unnumbered{\parsearg\unnumberedzzz}
+\def\unnumberedzzz #1{\seccheck{unnumbered}%
+\secno=0 \subsecno=0 \subsubsecno=0 \message{(#1)}
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\unnumbnoderef %
+}
+
+\outer\def\section{\parsearg\sectionzzz}
+\def\sectionzzz #1{\seccheck{section}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash secentry %
+{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}
+
+\outer\def\appendixsection{\parsearg\appendixsectionzzz}
+\outer\def\appendixsec{\parsearg\appendixsectionzzz}
+\def\appendixsectionzzz #1{\seccheck{appendixsection}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash secentry %
+{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedseczzz}
+\def\unnumberedseczzz #1{\seccheck{unnumberedsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\subsection{\parsearg\subsectionzzz}
+\def\subsectionzzz #1{\seccheck{subsection}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubseczzz}
+\def\appendixsubseczzz #1{\seccheck{appendixsubsec}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\subsubsection{\parsearg\subsubsectionzzz}
+\def\subsubsectionzzz #1{\seccheck{subsubsection}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsubsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%\
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubseczzz}
+\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsubsecentry{#1}%
+{\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%\
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+% Define @majorheading, @heading and @subheading
+
+\outer\def\majorheading #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \line{\chaprm #1\hfill}}\bigskip \par\penalty 200}
+
+\outer\def\chapheading #1{\chapbreak %
+{\chapfonts \line{\chaprm #1\hfill}}\bigskip \par\penalty 200}
+
+\let\heading=\secheadingi
+\let\subheading=\subsecheadingi
+\let\subsubheading=\subsubsecheadingi
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGodd{
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain}
+
+\def\chfplain #1#2{%
+\pchapsepmacro %
+{\chapfonts \line{\chaprm #2.\enspace #1\hfill}}\bigskip \par\penalty 5000 %
+}
+
+\def\unnchfplain #1{%
+\pchapsepmacro %
+{\chapfonts \line{\chaprm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \line{\chaprm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen}
+
+% Parameter controlling skip before section headings.
+
+\newskip \subsecheadingskip  \subsecheadingskip = 17pt plus 8pt minus 4pt
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+
+\newskip \secheadingskip  \secheadingskip = 21pt plus 8pt minus 4pt
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+
+\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}}
+\def\plainsecheading #1{\secheadingi {#1}}
+\def\secheadingi #1{{\advance \secheadingskip by \parskip %
+\secheadingbreak}%
+{\secfonts \line{\secrm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+\def\subsecheading #1#2#3#4{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\secfonts \line{\secrm#2.#3.#4\enspace #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+\def\subsubsecfonts{\subsecfonts} % Maybe this should change
+
+\def\subsubsecheading #1#2#3#4#5{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\secfonts \line{\secrm#2.#3.#4.#5\enspace #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000}
+
+\message{toc printing,}
+
+\def\Dotsbox{\hbox to 1em{\hss.\hss}} % Used by index macros
+
+\def\finishcontents{%
+\ifnum\pageno>0 %
+\pagealignmacro %
+\immediate\closeout \contentsfile%
+\pageno=-1             % Request roman numbered pages
+\fi}
+
+\outer\def\contents{%
+\finishcontents %
+\unnumbchapmacro{Table of Contents}
+\def\thischapter{Table of Contents}
+{\catcode`\\=0
+\catcode`\{=1          % Set up to handle contents files properly
+\catcode`\}=2
+\catcode`\@=11
+\input \jobname.toc
+}
+\vfill \eject}
+
+\outer\def\summarycontents{%
+\finishcontents %
+\unnumbchapmacro{Summary Table of Contents}
+\def\thischapter{Summary Table of Contents}
+{\catcode`\\=0
+\catcode`\{=1          % Set up to handle contents files properly
+\catcode`\}=2
+\catcode`\@=11
+\def\smallbreak{}
+\def\secentry ##1##2##3##4{}
+\def\subsecentry ##1##2##3##4##5{}
+\def\subsubsecentry ##1##2##3##4##5##6{}
+\def\unnumbsecentry ##1##2{}
+\def\unnumbsubsecentry ##1##2{}
+\def\unnumbsubsubsecentry ##1##2{}
+\let\medbreak=\smallbreak
+\input \jobname.toc
+}
+\vfill \eject}
+
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+% These macros generate individual entries in the table of contents
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+\def\chapentry #1#2#3{%
+\medbreak
+\line{#2.\space#1\leaders\hbox to 1em{\hss.\hss}\hfill #3}
+}
+
+\def\unnumbchapentry #1#2{%
+\medbreak
+\line{#1\leaders\Dotsbox\hfill #2}
+}
+
+\def\secentry #1#2#3#4{%
+\line{\enspace\enspace#2.#3\space#1\leaders\Dotsbox\hfill#4}
+}
+
+\def\unnumbsecentry #1#2{%
+\line{\enspace\enspace#1\leaders\Dotsbox\hfill #2}
+}
+
+\def\subsecentry #1#2#3#4#5{%
+\line{\enspace\enspace\enspace\enspace
+#2.#3.#4\space#1\leaders\Dotsbox\hfill #5}
+}
+
+\def\unnumbsubsecentry #1#2{%
+\line{\enspace\enspace\enspace\enspace#1\leaders\Dotsbox\hfill #2}
+}
+
+\def\subsubsecentry #1#2#3#4#5#6{%
+\line{\enspace\enspace\enspace\enspace\enspace\enspace
+#2.#3.#4.#5\space#1\leaders\Dotsbox\hfill #6}
+}
+
+\def\unnumbsubsubsecentry #1#2{%
+\line{\enspace\enspace\enspace\enspace\enspace\enspace#1\leaders\Dotsbox\hfill #2}
+}
+
+\message{environments,}
+
+% @tex ... @end tex    escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+\catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+\catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+\catcode `\%=14
+\catcode`\"=12
+\catcode`\|=12
+\catcode`\<=12
+\catcode`\>=12
+\escapechar=`\\
+%
+\let\{=\ptexlbrace
+\let\}=\ptexrbrace
+\let\.=\ptexdot
+\let\*=\ptexstar
+\def\@={@}%
+\let\bullet=\ptexbullet
+\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl
+\let\L=\ptexL
+%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^M gets inside @lisp
+% phr: changed space to \null, to avoid overfull hbox problems.
+{\obeyspaces%
+\gdef\lisppar{\null\endgraf}}
+
+% Cause \obeyspaces to make each Space cause a word-separation
+% rather than the default which is that it acts punctuation.
+% This is because space in tt font looks funny.
+{\obeyspaces %
+\gdef\sepspaces{\def {\ }}}
+
+\newskip\aboveenvskipamount \aboveenvskipamount= 0pt
+\def\aboveenvbreak{{\advance\aboveenvskipamount by \parskip
+\endgraf \ifdim\lastskip<\aboveenvskipamount
+\removelastskip \penalty-50 \vskip\aboveenvskipamount \fi}}
+
+\def\afterenvbreak{\endgraf \ifdim\lastskip<\aboveenvskipamount
+\removelastskip \penalty-50 \vskip\aboveenvskipamount \fi}
+
+\def\lisp{\aboveenvbreak\begingroup\inENV %This group ends at the end of the @lisp body
+\hfuzz=12truept % Don't be fussy
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Elisp{\endgroup\afterenvbreak}%
+\parskip=0pt \advance \rightskip by \lispnarrowing 
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines \tt \rawbackslash
+\def\next##1{}\next}
+
+
+\let\example=\lisp
+\def\Eexample{\Elisp}
+
+\let\smallexample=\lisp
+\def\Esmallexample{\Elisp}
+
+% Macro for 9 pt. examples, necessary to print with 5" lines.
+% From Pavel@xerox.  This is not really used unless the
+% @smallbook command is given.
+
+\def\smalllispx{\aboveenvbreak\begingroup\inENV
+%                      This group ends at the end of the @lisp body
+\hfuzz=12truept % Don't be fussy
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Esmalllisp{\endgroup\afterenvbreak}%
+\parskip=0pt \advance \rightskip by \lispnarrowing 
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines \ninett \rawbackslash
+\def\next##1{}\next}
+
+% This is @display; same as @lisp except use roman font.
+
+\def\display{\begingroup\inENV %This group ends at the end of the @display body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Edisplay{\endgroup\afterenvbreak}%
+\parskip=0pt \advance \rightskip by \lispnarrowing 
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% This is @format; same as @lisp except use roman font and don't narrow margins
+
+\def\format{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Eformat{\endgroup\afterenvbreak}
+\parskip=0pt \parindent=0pt
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% @flushleft and @flushright
+
+\def\flushleft{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+% This also causes @ to work when the directive name
+% is terminated by end of line.
+\let\par=\lisppar
+\def\Eflushleft{\endgroup\afterenvbreak}%
+\parskip=0pt \parindent=0pt
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+\def\flushright{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+% This also causes @ to work when the directive name
+% is terminated by end of line.
+\let\par=\lisppar
+\def\Eflushright{\endgroup\afterenvbreak}%
+\parskip=0pt \parindent=0pt
+\advance \leftskip by 0pt plus 1fill
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% @quotation - narrow the margins.
+
+\def\quotation{\begingroup\inENV %This group ends at the end of the @quotation body
+{\parskip=0pt  % because we will skip by \parskip too, later
+\aboveenvbreak}%
+\singlespace
+\parindent=0pt
+\def\Equotation{\par\endgroup\afterenvbreak}%
+\advance \rightskip by \lispnarrowing 
+\advance \leftskip by \lispnarrowing}
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=36pt
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested %
+\global\advance\parencount by 1 }
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+% also in that case restore the outer-level definition of (.
+\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+\global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\&#1}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text.  This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&}
+\def\lbrb{{\tt\char`\[}} \def\rbrb{{\tt\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+\leftskip = 0in  %
+\noindent        %
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1     %
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}%
+\tolerance=10000 \hbadness=10000    % Make all lines underfull and no complaints
+{\df #1}\enskip        % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+%    such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in \leftskip=\defbodyindent %
+\begingroup\obeylines\activeparens\spacesplit#3}
+
+\def\defmethparsebody #1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in \leftskip=\defbodyindent %
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+%  the first is all of #2 before the space token,
+%  the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl #1%
+\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi%
+\interlinepenalty=10000
+\endgraf\vskip -\parskip \penalty 10000}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Function}%
+\defunargs {#2}\endgroup %
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Macro}%
+\defunargs {#2}\endgroup %
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Special form}%
+\defunargs {#2}\endgroup %
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop {Funny Method} foo-class frobnicate argument
+
+\def\defop #1 {\def\defoptype{#1}%
+\defmethparsebody\Edefop\defopx\defopheader}
+
+\def\defopheader #1#2#3{\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{} on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defmethod == @defop Method
+
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+
+\def\defmethodheader #1#2#3{\dosubind {fn}{\code{#2}}{on #1}% entry in function index
+\begingroup\defname {#2}{Operation on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defmethparsebody\Edefcv\defcvx\defcvheader}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defmethparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{Instance variable of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\vskip -\parskip \penalty 10000}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defmethparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{Variable}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{User Option}%
+\defvarargs {#2}\endgroup %
+}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\defmethparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+\message{cross reference,}
+% Define cross-reference macros
+\newwrite \auxfile
+
+% \setref{foo} defines a cross-reference point named foo.
+
+\def\setref#1{%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ysectionnumberandtype}}
+
+\def\unnumbsetref#1{%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ynothing}}
+
+% \xref and \pxref generate cross references to specified points.
+
+\def\pxref #1{see \xrefX [#1,,,,,,,]}
+\def\xref #1{See \xrefX [#1,,,,,,,]}
+\def\xrefX [#1,#2,#3,#4,#5,#6]{%
+\setbox1=\hbox{\i{\losespace#5{}}}%
+\setbox0=\hbox{\losespace#3{}}%
+\ifdim \wd0 =0pt \setbox0=\hbox{\losespace#1{}}\fi%
+\ifdim \wd1 >0pt%
+section \unhbox0{} in \unhbox1%
+\else%
+\refx{#1-snt} [\unhbox0], page\tie \refx{#1-pg}%
+\fi }
+
+% \dosetq is the interface for calls from other macros
+
+\def\dosetq #1#2{{\let\folio=0%
+\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}%
+\next}}
+
+% \internalsetq {foo}{page} expands into CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 chapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 section\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+section\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+section\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Define @refx to reference a specific cross-reference string.
+
+\def\refx#1{%
+{%
+\expandafter\ifx\csname X#1\endcsname\relax
+% If not defined, say something at least.
+\expandafter\gdef\csname X#1\endcsname {$<$undefined$>$}%
+\message {WARNING: Cross-reference "#1" used but not yet defined}%
+\message {}%
+\fi %
+\csname X#1\endcsname %It's defined, so just use it.
+}}
+
+% Read the last existing aux file, if any.  No error if none exists.
+
+% This is the macro invoked by entries in the aux file.
+\def\xrdef #1#2{
+{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}}
+
+{
+\catcode `\^^@=\other
+\catcode `\\ 1=\other
+\catcode `\\ 2=\other
+\catcode `\^^C=\other
+\catcode `\^^D=\other
+\catcode `\^^E=\other
+\catcode `\^^F=\other
+\catcode `\^^G=\other
+\catcode `\^^H=\other
+\catcode `\\v=\other
+\catcode `\^^L=\other
+\catcode `\\ e=\other
+\catcode `\\ f=\other
+\catcode `\\10=\other
+\catcode `\\11=\other
+\catcode `\\12=\other
+\catcode `\\13=\other
+\catcode `\\14=\other
+\catcode `\\15=\other
+\catcode `\\16=\other
+\catcode `\\17=\other
+\catcode `\\18=\other
+\catcode `\\19=\other
+\catcode `\\1a=\other
+\catcode `\^^[=\other
+\catcode `\^^\=\other
+\catcode `\^^]=\other
+\catcode `\^^^=\other
+\catcode `\^^_=\other
+\catcode `\@=\other
+\catcode `\^=\other
+\catcode `\~=\other
+\catcode `\[=\other
+\catcode `\]=\other
+\catcode`\"=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode `\$=\other
+\catcode `\#=\other
+\catcode `\&=\other
+
+% the aux file uses ' as the escape.
+% Turn off \ as an escape so we do not lose on
+% entries which were dumped with control sequences in their names.
+% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+% Reference to such entries still does not work the way one would wish,
+% but at least they do not bomb out when the aux file is read in.
+
+\catcode `\{=1 \catcode `\}=2
+\catcode `\%=\other
+\catcode `\'=0
+\catcode `\\=\other
+
+'openin 1 'jobname.aux
+'ifeof 1 'else 'closein 1 'input 'jobname.aux
+'fi
+}
+
+% Open the new aux file.  Tex will close it automatically at exit.
+
+\openout \auxfile=\jobname.aux
+
+% Footnotes.
+
+\newcount \footnoteno
+
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+\gdef\footnote{\global\advance \footnoteno by \@ne
+\edef\thisfootno{$^{\the\footnoteno}$}%
+\let\@sf\empty
+\ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+\thisfootno\@sf\parsearg\footnotezzz}
+
+\gdef\footnotezzz #1{\insert\footins{
+\interlinepenalty\interfootnotelinepenalty
+\splittopskip\ht\strutbox % top baseline for broken footnotes
+\splitmaxdepth\dp\strutbox \floatingpenalty\@MM
+\leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip
+\footstrut\hang\textindent{\thisfootno}#1\strut}}
+
+}%end \catcode `\@=11
+
+% End of control word definitions.
+
+\message{and turning on texinfo input format.}
+
+\newindex{cp}
+\newcodeindex{fn}
+\newcodeindex{vr}
+\newcodeindex{tp}
+\newcodeindex{ky}
+\newcodeindex{pg}
+
+% Set some numeric style parameters, for 8.5 x 11 format.
+
+\hsize = 6.5in
+\parindent 15pt
+\parskip 18pt plus 1pt
+\baselineskip 15pt
+\advance\topskip by 1.2cm
+
+% Prevent underfull vbox error messages.
+\vbadness=10000
+
+% Use @smallbook to reset parameters for 7x9.5 format
+\def\smallbook{
+\global\lispnarrowing = 0.3in
+\global\baselineskip 12pt
+\global\parskip 3pt plus 1pt
+\global\hsize = 5in
+\global\doublecolumnhsize=2.4in \global\doublecolumnvsize=15.0in
+\global\vsize=7.5in
+\global\tolerance=700
+\global\hfuzz=1pt
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+\global\font\ninett=cmtt9
+
+\global\let\smalllisp=\smalllispx
+\global\let\smallexample=\smalllispx
+\global\def\Esmallexample{\Esmalllisp}
+}
+
+%% For a final copy, take out the rectangles
+%% that mark overfull boxes (in case you have decided
+%% that the text looks ok even though it passes the margin).
+\def\finalout{\overfullrule=0pt}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary)
+% Define certain chars to be always in tt font.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt \char '042}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt \char '176}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+\catcode`\_=\active
+\def_{{\tt \char '137}}
+\catcode`\|=\active
+\def|{{\tt \char '174}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+{\catcode`\\=\other
+@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+%% These look ok in all fonts, so just make them not special.  The @rm below
+%% makes sure that the current font starts out as the newly loaded cmr10
+\catcode`\$=\other \catcode`\%=\other \catcode`\&=\other \catcode`\#=\other
+
+\catcode 17=0   @c Define control-q
+\catcode`\\=\active
+@let\=@normalbackslash
+
+@textfonts
+@rm
diff --git a/lib/et/vfprintf.c b/lib/et/vfprintf.c
new file mode 100644 (file)
index 0000000..94f0fb5
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vfprintf.c 5.2 (Berkeley) 6/27/88";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <varargs.h>
+
+int
+vfprintf(iop, fmt, ap)
+       FILE *iop;
+       char *fmt;
+       va_list ap;
+{
+       int len;
+       char localbuf[BUFSIZ];
+
+       if (iop->_flag & _IONBF) {
+               iop->_flag &= ~_IONBF;
+               iop->_ptr = iop->_base = localbuf;
+               len = _doprnt(fmt, ap, iop);
+               (void) fflush(iop);
+               iop->_flag |= _IONBF;
+               iop->_base = NULL;
+               iop->_bufsiz = 0;
+               iop->_cnt = 0;
+       } else
+               len = _doprnt(fmt, ap, iop);
+
+       return (ferror(iop) ? EOF : len);
+}
diff --git a/lib/ext2fs/.depend b/lib/ext2fs/.depend
new file mode 100644 (file)
index 0000000..653e191
--- /dev/null
@@ -0,0 +1,350 @@
+alloc.o : alloc.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h \
+  /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/time.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../ext2fs/io.h ../ext2fs/ext2_err.h \
+  ../ext2fs/bitops.h 
+badblocks.o : badblocks.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/time.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../ext2fs/io.h ../ext2fs/ext2_err.h \
+  ../ext2fs/bitops.h 
+bb_inode.o : bb_inode.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/time.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../ext2fs/io.h ../ext2fs/ext2_err.h \
+  ../ext2fs/bitops.h 
+bitmaps.o : bitmaps.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/time.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../ext2fs/io.h ../ext2fs/ext2_err.h \
+  ../ext2fs/bitops.h 
+bitops.o : bitops.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/linux/fs.h /usr/include/linux/linkage.h /usr/include/linux/limits.h \
+  /usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
+  /usr/include/linux/net.h /usr/include/linux/socket.h /usr/include/linux/sockios.h \
+  /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
+  /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h \
+  /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \
+  /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h \
+  /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h \
+  /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
+  /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h \
+  ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+block.o : block.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/linux/fs.h /usr/include/linux/linkage.h \
+  /usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/dirent.h \
+  /usr/include/linux/vfs.h /usr/include/linux/net.h /usr/include/linux/socket.h \
+  /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
+  /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h \
+  /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
+  /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h \
+  /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h \
+  /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
+  /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h \
+  /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+closefs.o : closefs.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h \
+  /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/time.h /usr/include/linux/fs.h /usr/include/linux/linkage.h /usr/include/linux/limits.h \
+  /usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
+  /usr/include/linux/net.h /usr/include/linux/socket.h /usr/include/linux/sockios.h \
+  /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
+  /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h \
+  /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \
+  /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h \
+  /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h \
+  /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
+  /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h \
+  ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+expanddir.o : expanddir.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/linux/fs.h /usr/include/linux/linkage.h \
+  /usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/dirent.h \
+  /usr/include/linux/vfs.h /usr/include/linux/net.h /usr/include/linux/socket.h \
+  /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
+  /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h \
+  /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
+  /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h \
+  /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h \
+  /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
+  /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h \
+  /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+ext2_err.o : ext2_err.c 
+freefs.o : freefs.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h \
+  /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/linux/fs.h /usr/include/linux/linkage.h /usr/include/linux/limits.h \
+  /usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
+  /usr/include/linux/net.h /usr/include/linux/socket.h /usr/include/linux/sockios.h \
+  /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
+  /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h \
+  /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \
+  /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h \
+  /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h \
+  /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
+  /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h \
+  ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+get_pathname.o : get_pathname.c /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/linux/fs.h /usr/include/linux/linkage.h /usr/include/linux/limits.h \
+  /usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
+  /usr/include/linux/net.h /usr/include/linux/socket.h /usr/include/linux/sockios.h \
+  /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
+  /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h \
+  /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \
+  /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h \
+  /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h \
+  /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
+  /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h \
+  ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+initialize.o : initialize.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/time.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../ext2fs/io.h ../ext2fs/ext2_err.h \
+  ../ext2fs/bitops.h 
+inline.o : inline.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/time.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../ext2fs/io.h ../ext2fs/ext2_err.h \
+  ../ext2fs/bitops.h 
+inode.o : inode.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/sys/stat.h /usr/include/linux/stat.h \
+  /usr/include/linux/fs.h /usr/include/linux/linkage.h /usr/include/linux/limits.h \
+  /usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
+  /usr/include/linux/net.h /usr/include/linux/socket.h /usr/include/linux/sockios.h \
+  /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
+  /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h \
+  /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \
+  /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h \
+  /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h \
+  /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
+  /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h \
+  ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+link.o : link.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/linux/fs.h /usr/include/linux/linkage.h \
+  /usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/dirent.h \
+  /usr/include/linux/vfs.h /usr/include/linux/net.h /usr/include/linux/socket.h \
+  /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
+  /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h \
+  /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
+  /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h \
+  /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h \
+  /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
+  /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h \
+  /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+mkdir.o : mkdir.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/time.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../ext2fs/io.h ../ext2fs/ext2_err.h \
+  ../ext2fs/bitops.h 
+namei.o : namei.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/linux/fs.h /usr/include/linux/linkage.h \
+  /usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/dirent.h \
+  /usr/include/linux/vfs.h /usr/include/linux/net.h /usr/include/linux/socket.h \
+  /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
+  /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h \
+  /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
+  /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h \
+  /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h \
+  /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
+  /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h \
+  /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+newdir.o : newdir.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/linux/fs.h /usr/include/linux/linkage.h \
+  /usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/dirent.h \
+  /usr/include/linux/vfs.h /usr/include/linux/net.h /usr/include/linux/socket.h \
+  /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
+  /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h \
+  /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
+  /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h \
+  /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h \
+  /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
+  /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h \
+  /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+openfs.o : openfs.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/time.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../ext2fs/io.h ../ext2fs/ext2_err.h \
+  ../ext2fs/bitops.h 
+read_bb.o : read_bb.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/time.h /usr/include/sys/stat.h /usr/include/linux/stat.h /usr/include/linux/fs.h \
+  /usr/include/linux/linkage.h /usr/include/linux/limits.h /usr/include/linux/wait.h \
+  /usr/include/linux/dirent.h /usr/include/linux/vfs.h /usr/include/linux/net.h \
+  /usr/include/linux/socket.h /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h \
+  /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h \
+  /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h \
+  /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h \
+  /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h \
+  /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h \
+  /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h \
+  /usr/include/linux/sysv_fs_sb.h /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../ext2fs/io.h ../ext2fs/ext2_err.h \
+  ../ext2fs/bitops.h 
+read_bb_file.o : read_bb_file.c /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/fcntl.h /usr/include/linux/fcntl.h /usr/include/time.h /usr/include/sys/stat.h \
+  /usr/include/linux/stat.h /usr/include/linux/fs.h /usr/include/linux/linkage.h \
+  /usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/dirent.h \
+  /usr/include/linux/vfs.h /usr/include/linux/net.h /usr/include/linux/socket.h \
+  /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
+  /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h \
+  /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
+  /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h \
+  /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h \
+  /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
+  /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h \
+  /usr/include/linux/ext2_fs.h ext2fs.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../ext2fs/io.h ../ext2fs/ext2_err.h ../ext2fs/bitops.h 
+unix_io.o : unix_io.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/time.h /usr/include/sys/stat.h /usr/include/linux/stat.h ../et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ext2_err.h io.h 
diff --git a/lib/ext2fs/Makefile b/lib/ext2fs/Makefile
new file mode 100644 (file)
index 0000000..82c7280
--- /dev/null
@@ -0,0 +1,80 @@
+include ../../MCONFIG
+
+COMPILE_ET=../et/compile_et
+
+CFLAGS_NO=     $(WFLAGS) -I..
+CFLAGS=                $(OPT) $(CFLAGS_NO)
+LDFLAGS=       $(OPT)
+
+ARCHIVE=ar r
+RANLIB=ranlib
+RM=rm -f
+MV=mv
+LN=ln -s
+
+OBJS= ext2_err.o openfs.o freefs.o closefs.o bitmaps.o inode.o unix_io.o \
+       block.o namei.o newdir.o mkdir.o \
+       get_pathname.o bitops.o link.o alloc.o expanddir.o inline.o \
+       initialize.o badblocks.o read_bb.o bb_inode.o read_bb_file.o
+
+HFILES= bitops.h ext2_err.h ext2fs.h io.h
+
+DISTFILES= Makefile *.c *.h image
+
+.c.o:
+       $(CC) $(CFLAGS) -c $*.c
+       $(CC) $(CFLAGS_NO) -pg -o profiled/$*.o -c $*.c
+#      $(CC) $(CFLAGS_NO) -checker -g -o checker/$*.o -c $*.c
+
+all: libext2fs.a libext2fs_p.a 
+
+libext2fs.a: $(OBJS)
+       $(RM) $@.bak
+       -$(MV) $@ $@.bak
+       $(ARCHIVE) $@ $(OBJS)
+       $(RANLIB) $@
+       $(RM) ../$@
+       $(LN) ext2fs/$@ ../$@
+
+libext2fs_p.a: $(OBJS)
+       $(RM) $@.bak
+       -$(MV) $@ $@.bak
+       (cd profiled; $(ARCHIVE) ../$@ $(OBJS))
+       $(RANLIB) $@
+       $(RM) ../$@
+       $(LN) ext2fs/$@ ../$@
+
+libext2fs_chk.a: $(OBJS)
+       $(RM) $@.bak
+       -$(MV) $@ $@.bak
+       (cd checker; $(ARCHIVE) ../$@ $(OBJS))
+       $(RANLIB) $@
+       $(RM) ../$@
+       $(LN) ext2fs/$@ ../$@
+
+ext2_err.c ext2_err.h: ext2_err.et
+       $(COMPILE_ET) ext2_err.et
+
+install:: all
+       $(INSTALLLIB) libext2fs.a ${DESTDIR}$(LIBDIR)/libext2fs.a
+       $(CHMOD) 644 ${DESTDIR}$(LIBDIR)/libext2fs.a
+       $(RANLIB) ${DESTDIR}$(LIBDIR)/libext2fs.a
+       $(CHMOD) $(LIBMODE) ${DESTDIR}$(LIBDIR)/libext2fs.a
+
+install:: $(HFILES)
+       @rm -rf ${DESTDIR}$(INCLDIR)/ext2fs
+       @mkdir ${DESTDIR}$(INCLDIR)/ext2fs
+       for i in $(HFILES); do \
+               $(INSTALLINC) $$i ${DESTDIR}$(INCLDIR)/ext2fs/$$i; \
+       done
+
+clean:
+       rm -f \#* *.s *.o *.a *~ *.bak core profiled/* checker/*
+
+really-clean: clean
+       rm -f .depend ext2_err.c ext2_err.h
+
+dep depend .depend: ext2_err.h
+       $(CC) -M $(CFLAGS) *.c >.depend
+
+include .depend
diff --git a/lib/ext2fs/alloc.c b/lib/ext2fs/alloc.c
new file mode 100644 (file)
index 0000000..c456ad1
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * alloc.c --- allocate new inodes, blocks for ext2fs
+ *
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+/*
+ * Right now, just search forward from the parent directory's block
+ * group to find the next free inode.
+ *
+ * Should have a special policy for directories.
+ */
+errcode_t ext2fs_new_inode(ext2_filsys fs, ino_t dir, int mode, char *map,
+                          ino_t *ret)
+{
+       int     dir_group = 0;
+       ino_t   i;
+       ino_t   start_inode;
+
+       if (!map)
+               map = fs->inode_map;
+       if (!map)
+               return EXT2_ET_NO_INODE_BITMAP;
+       
+       if (dir > 0) 
+               dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super);
+
+       start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->super)) + 1;
+       i = start_inode;
+       if (i < EXT2_FIRST_INO)
+               i = EXT2_FIRST_INO;
+
+       do {
+               if (!ext2fs_test_inode_bitmap(fs, map, i))
+                       break;
+               i++;
+               if (i > fs->super->s_inodes_count)
+                       i = EXT2_FIRST_INO;
+       } while (i != start_inode);
+       
+       if (ext2fs_test_inode_bitmap(fs, map, i))
+               return ENOSPC;
+       *ret = i;
+       return 0;
+}
+
+/*
+ * Stupid algorithm --- we now just search forward starting from the
+ * goal.  Should put in a smarter one someday....
+ */
+errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, char *map, blk_t *ret)
+{
+       blk_t   i = goal;
+
+       if (!map)
+               map = fs->block_map;
+       if (!map)
+               return EXT2_ET_NO_BLOCK_BITMAP;
+       if (!i)
+               i = fs->super->s_first_data_block;
+       do {
+               if (!ext2fs_test_block_bitmap(fs, map, i)) {
+                       *ret = i;
+                       return 0;
+               }
+               i++;
+               if (i > fs->super->s_blocks_count)
+                       i = fs->super->s_first_data_block;
+       } while (i != goal);
+       return ENOSPC;
+}
+
+static int check_blocks_free(ext2_filsys fs, char *map, blk_t blk, int num)
+{
+       int     i;
+
+       for (i=0; i < num; i++) {
+               if ((blk+i) > fs->super->s_blocks_count)
+                       return 0;
+               if (ext2fs_test_block_bitmap(fs, map, blk+i))
+                       return 0;
+       }
+       return 1;
+}
+
+errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
+                                int num, char *map, blk_t *ret)
+{
+       blk_t   b = start;
+
+       if (!map)
+               map = fs->block_map;
+       if (!map)
+               return EXT2_ET_NO_BLOCK_BITMAP;
+       if (!b)
+               b = fs->super->s_first_data_block;
+       if (!finish)
+               finish = start;
+       if (!num)
+               num = 1;
+       do {
+               if (check_blocks_free(fs, map, b, num)) {
+                       *ret = b;
+                       return 0;
+               }
+               b++;
+               if (b > fs->super->s_blocks_count)
+                       b = fs->super->s_first_data_block;
+       } while (b != finish);
+       return ENOSPC;
+}
+
diff --git a/lib/ext2fs/badblocks.c b/lib/ext2fs/badblocks.c
new file mode 100644 (file)
index 0000000..5e8cd43
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * badblocks.c --- routines to manipulate the bad block structure
+ * 
+ * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+/*
+ * This procedure create an empty badblocks list.
+ */
+errcode_t badblocks_list_create(badblocks_list *ret, int size)
+{
+       badblocks_list  bb;
+
+       bb = malloc(sizeof(struct struct_badblocks_list));
+       if (!bb)
+               return ENOMEM;
+       memset(bb, 0, sizeof(struct struct_badblocks_list));
+       bb->size = size ? size : 10;
+       bb->list = malloc(bb->size * sizeof(blk_t));
+       if (!bb->list) {
+               free(bb);
+               return ENOMEM;
+       }
+       *ret = bb;
+       return 0;
+}
+
+/*
+ * This procedure frees a badblocks list.
+ */
+void badblocks_list_free(badblocks_list bb)
+{
+       if (bb->list)
+               free(bb->list);
+       bb->list = 0;
+       free(bb);
+}
+
+/*
+ * This procedure adds a block to a badblocks list.
+ */
+errcode_t badblocks_list_add(badblocks_list bb, blk_t blk)
+{
+       int     i;
+
+       for (i=0; i < bb->num; i++)
+               if (bb->list[i] == blk)
+                       return 0;
+
+       if (bb->num >= bb->size) {
+               bb->size += 10;
+               bb->list = realloc(bb->list, bb->size * sizeof(blk_t));
+               if (!bb->list) {
+                       bb->size = 0;
+                       bb->num = 0;
+                       return ENOMEM;
+               }
+       }
+
+       bb->list[bb->num++] = blk;
+       return 0;
+}
+
+/*
+ * This procedure tests to see if a particular block is on a badblocks
+ * list.
+ */
+int badblocks_list_test(badblocks_list bb, blk_t blk)
+{
+       int     i;
+
+       for (i=0; i < bb->num; i++)
+               if (bb->list[i] == blk)
+                       return 1;
+
+       return 0;
+}
+
+errcode_t badblocks_list_iterate_begin(badblocks_list bb,
+                                      badblocks_iterate *ret)
+{
+       badblocks_iterate iter;
+
+       iter = malloc(sizeof(struct struct_badblocks_iterate));
+       if (!iter)
+               return ENOMEM;
+
+       iter->bb = bb;
+       iter->ptr = 0;
+       *ret = iter;
+       return 0;
+}
+
+int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk)
+{
+       badblocks_list  bb = iter->bb;
+       
+       if (iter->ptr < bb->num) {
+               *blk = bb->list[iter->ptr++];
+               return 1;
+       } 
+       *blk = 0;
+       return 0;
+}
+
+void badblocks_list_iterate_end(badblocks_iterate iter)
+{
+       iter->bb = 0;
+       free(iter);
+}
+
+
+
+
+               
diff --git a/lib/ext2fs/bb_inode.c b/lib/ext2fs/bb_inode.c
new file mode 100644 (file)
index 0000000..d345f1d
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * bb_inode.c --- routines to update the bad block inode.
+ * 
+ * WARNING: This routine modifies a lot of state in the filesystem; if
+ * this routine returns an error, the bad block inode may be in an
+ * inconsistent state.
+ * 
+ * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+struct set_badblock_record {
+       badblocks_iterate       bb_iter;
+       int             bad_block_count;
+       blk_t           *ind_blocks;
+       int             max_ind_blocks;
+       int             ind_blocks_size;
+       int             ind_blocks_ptr;
+       char            *block_buf;
+       errcode_t       err;
+};
+
+static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, int blockcnt,
+                             void *private);
+static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, int blockcnt,
+                            void *private);
+       
+/*
+ * Given a bad blocks bitmap, update the bad blocks inode to reflect
+ * the map.
+ */
+errcode_t ext2fs_update_bb_inode(ext2_filsys fs, badblocks_list bb_list)
+{
+       errcode_t                       retval;
+       struct set_badblock_record      rec;
+       struct ext2_inode               inode;
+       
+       if (!fs->block_map)
+               return EXT2_ET_NO_BLOCK_BITMAP;
+       
+       rec.bad_block_count = 0;
+       rec.ind_blocks_size = rec.ind_blocks_ptr = 0;
+       rec.max_ind_blocks = 10;
+       rec.ind_blocks = malloc(rec.max_ind_blocks * sizeof(blk_t));
+       if (!rec.ind_blocks)
+               return ENOMEM;
+       memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
+       rec.block_buf = malloc(fs->blocksize);
+       if (!rec.block_buf) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+       memset(rec.block_buf, 0, fs->blocksize);
+       rec.err = 0;
+       
+       /*
+        * First clear the old bad blocks (while saving the indirect blocks) 
+        */
+       retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0,
+                                     clear_bad_block_proc, &rec);
+       if (retval)
+               goto cleanup;
+       if (rec.err) {
+               retval = rec.err;
+               goto cleanup;
+       }
+       
+       /*
+        * Now set the bad blocks!
+        */
+       if (bb_list) {
+               retval = badblocks_list_iterate_begin(bb_list, &rec.bb_iter);
+               if (retval)
+                       goto cleanup;
+               retval = ext2fs_block_iterate(fs, EXT2_BAD_INO,
+                                             BLOCK_FLAG_APPEND, 0,
+                                             set_bad_block_proc, &rec);
+               badblocks_list_iterate_end(rec.bb_iter);
+               if (retval) 
+                       goto cleanup;
+               if (rec.err) {
+                       retval = rec.err;
+                       goto cleanup;
+               }
+       }
+       
+       /*
+        * Update the bad block inode's mod time and block count
+        * field.  
+        */
+       retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
+       if (retval)
+               goto cleanup;
+       
+       inode.i_atime = inode.i_mtime = time(0);
+       if (!inode.i_ctime)
+               inode.i_ctime = time(0);
+       inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512);
+       inode.i_size = rec.bad_block_count * fs->blocksize;
+
+       retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
+       if (retval)
+               goto cleanup;
+       
+cleanup:
+       free(rec.ind_blocks);
+       free(rec.block_buf);
+       return retval;
+}
+
+/*
+ * Helper function for update_bb_inode()
+ *
+ * Clear the bad blocks in the bad block inode, while saving the
+ * indirect blocks.
+ */
+static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, int blockcnt,
+                               void *private)
+{
+       struct set_badblock_record *rec = (struct set_badblock_record *)
+               private;
+       int     group;
+
+       if (!*block_nr)
+               return 0;
+
+       if (blockcnt < 0) {
+               if (rec->ind_blocks_size >= rec->max_ind_blocks) {
+                       rec->max_ind_blocks += 10;
+                       rec->ind_blocks = realloc(rec->ind_blocks,
+                                                 rec->max_ind_blocks *
+                                                 sizeof(blk_t));
+                       if (!rec->ind_blocks) {
+                               rec->err = ENOMEM;
+                               return BLOCK_ABORT;
+                       }
+               }
+               rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
+       }
+
+       /*
+        * Mark the block as unused, and update accounting information
+        */
+       ext2fs_unmark_block_bitmap(fs, fs->block_map, *block_nr);
+       ext2fs_mark_bb_dirty(fs);
+       group = ext2fs_group_of_blk(fs, *block_nr);
+       fs->group_desc[group].bg_free_blocks_count++;
+       fs->super->s_free_blocks_count++;
+       ext2fs_mark_super_dirty(fs);
+       
+       *block_nr = 0;
+       return BLOCK_CHANGED;
+}
+
+       
+/*
+ * Helper function for update_bb_inode()
+ *
+ * Set the block list in the bad block inode, using the supplied bitmap.
+ */
+static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
+                        int blockcnt, void *private)
+{
+       struct set_badblock_record *rec = (struct set_badblock_record *)
+               private;
+       errcode_t       retval;
+       blk_t           blk;
+       int             group;
+
+       if (blockcnt >= 0) {
+               /*
+                * Get the next bad block.
+                */
+               if (!badblocks_list_iterate(rec->bb_iter, &blk))
+                       return BLOCK_ABORT;
+               rec->bad_block_count++;
+       } else if (rec->ind_blocks_ptr < rec->ind_blocks_size)
+               /*
+                * An indirect block; fetch a block from the
+                * previously used indirect block list.
+                */
+               blk = rec->ind_blocks[rec->ind_blocks_ptr++];
+       else {
+               /*
+                * An indirect block, and we're out of reserved
+                * indirect blocks.  Allocate a new one.
+                */
+               retval = ext2fs_new_block(fs, 0, 0, &blk);
+               if (retval) {
+                       rec->err = retval;
+                       return BLOCK_ABORT;
+               }
+               retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf);
+               if (retval) {
+                       rec->err = retval;
+                       return BLOCK_ABORT;
+               }
+       }
+       
+       /*
+        * Mark the block as used, and update block counts
+        */
+       ext2fs_mark_block_bitmap(fs, fs->block_map, blk); 
+       ext2fs_mark_bb_dirty(fs);
+       group = ext2fs_group_of_blk(fs, blk);
+       fs->group_desc[group].bg_free_blocks_count--;
+       fs->super->s_free_blocks_count--;
+       ext2fs_mark_super_dirty(fs);
+       
+       *block_nr = blk;
+       return BLOCK_CHANGED;
+}
+
+
+
+
+
+
diff --git a/lib/ext2fs/bitmaps.c b/lib/ext2fs/bitmaps.c
new file mode 100644 (file)
index 0000000..c12433a
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * bitmaps.c --- routines to read, write, and manipulate the inode and
+ * block bitmaps.
+ *
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
+{
+       int             i;
+       int             nbytes;
+       errcode_t       retval;
+       char * inode_bitmap = fs->inode_map;
+       char * bitmap_block = NULL;
+
+       if (!(fs->flags & EXT2_FLAG_RW))
+               return EXT2_ET_RO_FILSYS;
+       if (!inode_bitmap)
+               return 0;
+       nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
+       bitmap_block = malloc(fs->blocksize);
+       if (!bitmap_block)
+               return ENOMEM;
+       memset(bitmap_block, 0xff, fs->blocksize);
+       for (i = 0; i < fs->group_desc_count; i++) {
+               memcpy(bitmap_block, inode_bitmap, nbytes);
+               retval = io_channel_write_blk(fs->io,
+                     fs->group_desc[i].bg_inode_bitmap, 1,
+                                             bitmap_block);
+               if (retval)
+                       return EXT2_ET_INODE_BITMAP_WRITE;
+               inode_bitmap += nbytes;
+       }
+       fs->flags |= EXT2_FLAG_CHANGED;
+       fs->flags &= ~EXT2_FLAG_IB_DIRTY;
+       free(bitmap_block);
+       return 0;
+}
+
+errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
+{
+       int             i;
+       int             j;
+       int             nbytes;
+       int             nbits;
+       errcode_t       retval;
+       char * block_bitmap = fs->block_map;
+       char * bitmap_block = NULL;
+
+       if (!(fs->flags & EXT2_FLAG_RW))
+               return EXT2_ET_RO_FILSYS;
+       if (!block_bitmap)
+               return 0;
+       nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+       bitmap_block = malloc(fs->blocksize);
+       if (!bitmap_block)
+               return ENOMEM;
+       memset(bitmap_block, 0xff, fs->blocksize);
+       for (i = 0; i < fs->group_desc_count; i++) {
+               memcpy(bitmap_block, block_bitmap, nbytes);
+               if (i == fs->group_desc_count - 1) {
+                       /* Force bitmap padding for the last group */
+                       nbits = (fs->super->s_blocks_count
+                                - fs->super->s_first_data_block)
+                               % EXT2_BLOCKS_PER_GROUP(fs->super);
+                       for (j = nbits; j < fs->blocksize * 8; j++)
+                               set_bit(j, bitmap_block);
+               }
+               retval = io_channel_write_blk(fs->io,
+                     fs->group_desc[i].bg_block_bitmap, 1,
+                                             bitmap_block);
+               if (retval)
+                       return EXT2_ET_BLOCK_BITMAP_WRITE;
+               block_bitmap += nbytes;
+       }
+       fs->flags |= EXT2_FLAG_CHANGED;
+       fs->flags &= ~EXT2_FLAG_BB_DIRTY;
+       free(bitmap_block);
+       return 0;
+}
+
+errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs)
+{
+       int i;
+       char * inode_bitmap;
+       char *buf = 0;
+       errcode_t       retval;
+       int nbytes;
+
+       fs->write_bitmaps = ext2fs_write_bitmaps;
+
+       if (fs->inode_map)
+               free(fs->inode_map);
+       nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
+       fs->flags &= ~EXT2_FLAG_IB_DIRTY;
+       fs->inode_map = malloc((nbytes * fs->group_desc_count) + 1);
+       if (!fs->inode_map)
+               return ENOMEM;
+       inode_bitmap = fs->inode_map;
+
+       buf = malloc(fs->blocksize);
+       if (!buf)
+               return ENOMEM;
+
+       for (i = 0; i < fs->group_desc_count; i++) {
+               retval = io_channel_read_blk(fs->io,
+                            fs->group_desc[i].bg_inode_bitmap, 1,
+                                            buf);
+               if (retval) {
+                       retval = EXT2_ET_INODE_BITMAP_READ;
+                       goto cleanup;
+               }
+               memcpy(inode_bitmap, buf, nbytes);
+               inode_bitmap += nbytes;
+       }
+       free(buf);
+       return 0;
+       
+cleanup:
+       free(fs->inode_map);
+       fs->inode_map = 0;
+       if (buf)
+               free(buf);
+       return retval;
+}
+
+errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
+{
+       int i;
+       char * block_bitmap;
+       char *buf = 0;
+       errcode_t retval;
+       int nbytes;
+
+       fs->write_bitmaps = ext2fs_write_bitmaps;
+
+       if (fs->block_map)
+               free(fs->block_map);
+       nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+       fs->flags &= ~EXT2_FLAG_BB_DIRTY;
+       fs->block_map = malloc((nbytes * fs->group_desc_count) + 1);
+       if (!fs->block_map)
+               return ENOMEM;
+       block_bitmap = fs->block_map;
+
+       buf = malloc(fs->blocksize);
+       if (!buf)
+               return ENOMEM;
+
+       for (i = 0; i < fs->group_desc_count; i++) {
+               retval = io_channel_read_blk(fs->io,
+                            fs->group_desc[i].bg_block_bitmap, 1,
+                                            buf);
+               if (retval) {
+                       retval = EXT2_ET_BLOCK_BITMAP_READ;
+                       goto cleanup;
+               }
+               memcpy(block_bitmap, buf, nbytes);
+               block_bitmap += nbytes;
+       }
+       free(buf);
+       return 0;
+       
+cleanup:
+       free(fs->block_map);
+       fs->block_map = 0;
+       if (buf)
+               free(buf);
+       return retval;
+}
+
+errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs, char **ret)
+{
+       char    *map;
+       int     size;
+       
+       fs->write_bitmaps = ext2fs_write_bitmaps;
+
+       size = (fs->super->s_inodes_count / 8) + 1;
+       map = malloc(size);
+       if (!map)
+               return ENOMEM;
+       memset(map, 0, size);
+       *ret = map;
+       return 0;
+}
+
+errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, char **ret)
+{
+       char    *map;
+       int     size;
+
+       fs->write_bitmaps = ext2fs_write_bitmaps;
+       
+       size = (fs->super->s_blocks_count / 8) + 1;
+       map = malloc(size);
+       if (!map)
+               return ENOMEM;
+       memset(map, 0, size);
+       *ret = map;
+       return 0;
+}
+
+errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
+{
+       errcode_t       retval;
+
+       fs->write_bitmaps = ext2fs_write_bitmaps;
+
+       if (!fs->inode_map) {
+               retval = ext2fs_read_inode_bitmap(fs);
+               if (retval)
+                       return retval;
+       }
+       if (!fs->block_map) {
+               retval = ext2fs_read_block_bitmap(fs);
+               if (retval)
+                       return retval;
+       }
+       return 0;
+}
+
+errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
+{
+       errcode_t       retval;
+
+       if (fs->block_map && ext2fs_test_bb_dirty(fs)) {
+               retval = ext2fs_write_block_bitmap(fs);
+               if (retval)
+                       return retval;
+       }
+       if (fs->inode_map && ext2fs_test_ib_dirty(fs)) {
+               retval = ext2fs_write_inode_bitmap(fs);
+               if (retval)
+                       return retval;
+       }
+       return 0;
+}      
+
+
+
+
+
diff --git a/lib/ext2fs/bitops.c b/lib/ext2fs/bitops.c
new file mode 100644 (file)
index 0000000..a53d8ee
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * bitops.c --- Bitmap frobbing code.  See bitops.h for the inlined
+ *     routines.
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ * 
+ * Taken from <asm/bitops.h>, Copyright 1992, Linus Torvalds.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+#if (!defined(__i386__) && !defined(__i486__) && !defined(__i586__))
+
+/*
+ * For the benefit of those who are trying to port Linux to another
+ * architecture, here are some C-language equivalents.  You should
+ * recode these in the native assmebly language, if at all possible.
+ * To guarantee atomicity, these routines call cli() and sti() to
+ * disable interrupts while they operate.  (You have to provide inline
+ * routines to cli() and sti().)
+ *
+ * Also note, these routines assume that you have 32 bit integers.
+ * You will have to change this if you are trying to port Linux to the
+ * Alpha architecture or to a Cray.  :-)
+ * 
+ * C language equivalents written by Theodore Ts'o, 9/26/92
+ */
+
+int set_bit(int nr,void * addr)
+{
+       int     mask, retval;
+       int     *ADDR = (int *) addr;
+
+       ADDR += nr >> 5;
+       mask = 1 << (nr & 0x1f);
+       cli();
+       retval = (mask & *ADDR) != 0;
+       *ADDR |= mask;
+       sti();
+       return retval;
+}
+
+int clear_bit(int nr, void * addr)
+{
+       int     mask, retval;
+       int     *ADDR = (int *) addr;
+
+       ADDR += nr >> 5;
+       mask = 1 << (nr & 0x1f);
+       cli();
+       retval = (mask & *ADDR) != 0;
+       *ADDR &= ~mask;
+       sti();
+       return retval;
+}
+
+int test_bit(int nr, const void * addr)
+{
+       int             mask;
+       const int       *ADDR = (const int *) addr;
+
+       ADDR += nr >> 5;
+       mask = 1 << (nr & 0x1f);
+       return ((mask & *ADDR) != 0);
+}
+#endif /* !i386 */
+
+/*
+ * These are routines print warning messages; they are called by
+ * inline routines.
+ */
+const char *ext2fs_block_string = "block";
+const char *ext2fs_inode_string = "inode";
+const char *ext2fs_mark_string = "mark";
+const char *ext2fs_unmark_string = "unmark";
+const char *ext2fs_test_string = "test";
+
+void ext2fs_warn_bitmap(ext2_filsys fs, const char *op, const char *type,
+                       int arg)
+{
+       char    func[80];
+
+       sprintf(func, "ext2fs_%s_%s_bitmap", op, type);
+       com_err(func, 0, "INTERNAL ERROR: illegal %s #%d for %s",
+               type, arg, fs->device_name);
+}
+
+
+
diff --git a/lib/ext2fs/bitops.h b/lib/ext2fs/bitops.h
new file mode 100644 (file)
index 0000000..c01cc86
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * bitops.h --- Bitmap frobbing code.
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ * 
+ * Taken from <asm/bitops.h>, Copyright 1992, Linus Torvalds.
+ */
+
+
+extern int set_bit(int nr,void * addr);
+extern int clear_bit(int nr, void * addr);
+extern int test_bit(int nr, const void * addr);
+
+/*
+ * EXT2FS bitmap manipulation routines.
+ */
+
+/* Support for sending warning messages from the inline subroutines */
+extern const char *ext2fs_block_string;
+extern const char *ext2fs_inode_string;
+extern const char *ext2fs_mark_string;
+extern const char *ext2fs_unmark_string;
+extern const char *ext2fs_test_string;
+extern void ext2fs_warn_bitmap(ext2_filsys fs, const char *op,
+                              const char *type, int arg);
+
+extern void ext2fs_mark_block_bitmap(ext2_filsys fs, char *bitmap, int block);
+extern void ext2fs_unmark_block_bitmap(ext2_filsys fs, char *bitmap,
+                                      int block);
+extern int ext2fs_test_block_bitmap(ext2_filsys fs, const char *bitmap,
+                                   int block);
+extern void ext2fs_mark_inode_bitmap(ext2_filsys fs, char *bitmap, int inode);
+extern void ext2fs_unmark_inode_bitmap(ext2_filsys fs, char *bitmap,
+                                      int inode);
+extern int ext2fs_test_inode_bitmap(ext2_filsys fs, const char *bitmap,
+                                   int inode);
+
+/*
+ * The inline routines themselves...
+ * 
+ * If NO_INLINE_FUNCS is defined, then we won't try to do inline
+ * functions at all!
+ */
+#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
+#ifdef INCLUDE_INLINE_FUNCS
+#define _INLINE_ extern
+#else
+#define _INLINE_ extern __inline__
+#endif
+
+#if (defined(__i386__) || defined(__i486__) || defined(__i586__))
+/*
+ * These are done by inline assembly for speed reasons.....
+ *
+ * All bitoperations return 0 if the bit was cleared before the
+ * operation and != 0 if it was not.  Bit 0 is the LSB of addr; bit 32
+ * is the LSB of (addr+1).
+ */
+
+/*
+ * Some hacks to defeat gcc over-optimizations..
+ */
+struct __dummy_h { unsigned long a[100]; };
+#define ADDR (*(struct __dummy_h *) addr)
+#define CONST_ADDR (*(const struct __dummy_h *) addr)  
+
+_INLINE_ int set_bit(int nr, void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"=m" (ADDR)
+               :"r" (nr));
+       return oldbit;
+}
+
+_INLINE_ int clear_bit(int nr, void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit),"=m" (ADDR)
+               :"r" (nr));
+       return oldbit;
+}
+
+_INLINE_ int test_bit(int nr, const void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit)
+               :"m" (CONST_ADDR),"r" (nr));
+       return oldbit;
+}
+
+#undef ADDR
+
+#endif /* i386 */
+
+_INLINE_ void ext2fs_mark_block_bitmap(ext2_filsys fs, char *bitmap,
+                                           int block)
+{
+       if ((block < fs->super->s_first_data_block) ||
+           (block >= fs->super->s_blocks_count)) {
+               ext2fs_warn_bitmap(fs, ext2fs_mark_string,
+                                  ext2fs_block_string, block);
+               return;
+       }
+       set_bit(block - fs->super->s_first_data_block, bitmap);
+}
+
+_INLINE_ void ext2fs_unmark_block_bitmap(ext2_filsys fs, char *bitmap,
+                                             int block)
+{
+       if ((block < fs->super->s_first_data_block) ||
+           (block >= fs->super->s_blocks_count)) {
+               ext2fs_warn_bitmap(fs, ext2fs_unmark_string,
+                                  ext2fs_block_string, block);
+               return;
+       }
+       clear_bit(block - fs->super->s_first_data_block, bitmap);
+}
+
+_INLINE_ int ext2fs_test_block_bitmap(ext2_filsys fs, const char *bitmap,
+                                     int block)
+{
+       if ((block < fs->super->s_first_data_block) ||
+           (block >= fs->super->s_blocks_count)) {
+               ext2fs_warn_bitmap(fs, ext2fs_test_string,
+                                  ext2fs_block_string, block);
+               return 0;
+       }
+       return test_bit(block - fs->super->s_first_data_block, bitmap);
+}
+
+_INLINE_ void ext2fs_mark_inode_bitmap(ext2_filsys fs, char *bitmap,
+                                           int inode)
+{
+       if ((inode < 1) || (inode > fs->super->s_inodes_count)) {
+               ext2fs_warn_bitmap(fs, ext2fs_mark_string,
+                                  ext2fs_inode_string, inode);
+               return;
+       }
+       set_bit(inode - 1, bitmap);
+}
+
+_INLINE_ void ext2fs_unmark_inode_bitmap(ext2_filsys fs, char *bitmap,
+                                             int inode)
+{
+       if ((inode < 1) || (inode > fs->super->s_inodes_count)) {
+               ext2fs_warn_bitmap(fs, ext2fs_unmark_string,
+                                  ext2fs_inode_string, inode);
+               return;
+       }
+       clear_bit(inode - 1, bitmap);
+}
+
+_INLINE_ int ext2fs_test_inode_bitmap(ext2_filsys fs, const char *bitmap,
+                                     int inode)
+{
+       if ((inode < 1) || (inode > fs->super->s_inodes_count)) {
+               ext2fs_warn_bitmap(fs, ext2fs_test_string,
+                                  ext2fs_inode_string, inode);
+               return 0;
+       }
+       return test_bit(inode - 1, bitmap);
+}
+
+#undef _INLINE_
+#endif
diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
new file mode 100644 (file)
index 0000000..d2c87ce
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * block.c --- iterate over all blocks in an inode
+ * 
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+struct block_context {
+       ext2_filsys     fs;
+       int (*func)(ext2_filsys fs,
+                   blk_t       *blocknr,
+                   int         bcount,
+                   void        *private);
+       int             bcount;
+       int             bsize;
+       int             flags;
+       errcode_t       errcode;
+       char    *ind_buf;
+       char    *dind_buf;
+       char    *tind_buf;
+       void    *private;
+};
+
+static int block_iterate_ind(blk_t *ind_block, struct block_context *ctx)
+{
+       int     ret = 0, changed = 0;
+       int     i, flags;
+       blk_t   *block_nr;
+
+       if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE))
+               ret = (*ctx->func)(ctx->fs, ind_block, -1, ctx->private);
+       if (!*ind_block || (ret & BLOCK_ABORT))
+               return ret;
+       ctx->errcode = io_channel_read_blk(ctx->fs->io, *ind_block,
+                                          1, ctx->ind_buf);
+       if (ctx->errcode) {
+               ret |= BLOCK_ERROR;
+               return ret;
+       }
+       for (i = 0; i < (ctx->fs->blocksize >> 2); i++, ctx->bcount++) {
+               block_nr = (blk_t *) ctx->ind_buf + i;
+               if (*block_nr || (ctx->flags & BLOCK_FLAG_APPEND)) {
+                       flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
+                                            ctx->private);
+                       changed |= flags & BLOCK_CHANGED;
+                       if (flags & BLOCK_ABORT) {
+                               ret |= BLOCK_ABORT;
+                               break;
+                       }
+               }
+       }
+       if (changed) {
+               ctx->errcode = io_channel_write_blk(ctx->fs->io, *ind_block,
+                                                   1, ctx->ind_buf);
+               if (ctx->errcode)
+                       ret |= BLOCK_ERROR | BLOCK_ABORT;
+       }
+       if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+           !(ret & BLOCK_ABORT))
+               ret |= (*ctx->func)(ctx->fs, ind_block, -1, ctx->private);
+       return ret;
+}
+       
+static int block_iterate_dind(blk_t *dind_block, struct block_context *ctx)
+{
+       int     ret = 0, changed = 0;
+       int     i, flags;
+       blk_t   *block_nr;
+
+       if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE))
+               ret = (*ctx->func)(ctx->fs, dind_block, -2, ctx->private);
+       if (!*dind_block || (ret & BLOCK_ABORT))
+               return ret;
+       ctx->errcode = io_channel_read_blk(ctx->fs->io, *dind_block,
+                                          1, ctx->dind_buf);
+       if (ctx->errcode) {
+               ret |= BLOCK_ERROR;
+               return ret;
+       }
+       for (i = 0; i < (ctx->fs->blocksize >> 2); i++) {
+               block_nr = (blk_t *) ctx->dind_buf + i;
+               if (*block_nr || (ctx->flags & BLOCK_FLAG_APPEND)) {
+                       flags = block_iterate_ind(block_nr, ctx);
+                       changed |= flags & BLOCK_CHANGED;
+                       if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+                               ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+                               break;
+                       }
+               }
+       }
+       if (changed) {
+               ctx->errcode = io_channel_write_blk(ctx->fs->io, *dind_block,
+                                                   1, ctx->dind_buf);
+               if (ctx->errcode)
+                       ret |= BLOCK_ERROR | BLOCK_ABORT;
+       }
+       if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+           !(ret & BLOCK_ABORT))
+               ret |= (*ctx->func)(ctx->fs, dind_block, -2, ctx->private);
+       return ret;
+}
+       
+static int block_iterate_tind(blk_t *tind_block, struct block_context *ctx)
+{
+       int     ret = 0, changed = 0;
+       int     i, flags;
+       blk_t   *block_nr;
+
+       if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE))
+               ret = (*ctx->func)(ctx->fs, tind_block, -3, ctx->private);
+       if (!*tind_block || (ret & BLOCK_ABORT))
+               return ret;
+       ctx->errcode = io_channel_read_blk(ctx->fs->io, *tind_block,
+                                          1, ctx->tind_buf);
+       if (ctx->errcode) {
+               ret |= BLOCK_ERROR;
+               return ret;
+       }
+       for (i = 0; i < (ctx->fs->blocksize >> 2); i++) {
+               block_nr = (blk_t *) ctx->tind_buf + i;
+               if (*block_nr || (ctx->flags & BLOCK_FLAG_APPEND)) {
+                       flags = block_iterate_dind(block_nr, ctx);
+                       if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+                               ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+                               break;
+                       }
+               }
+       }
+       if (changed) {
+               ctx->errcode = io_channel_write_blk(ctx->fs->io, *tind_block,
+                                                   1, ctx->tind_buf);
+               if (ctx->errcode)
+                       ret |= BLOCK_ERROR | BLOCK_ABORT;
+       }
+       if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+           !(ret & BLOCK_ABORT))
+               ret |= (*ctx->func)(ctx->fs, tind_block, -3, ctx->private);
+       
+       return ret;
+}
+       
+errcode_t ext2fs_block_iterate(ext2_filsys fs,
+                              ino_t    ino,
+                              int      flags,
+                              char *block_buf,
+                              int (*func)(ext2_filsys fs,
+                                          blk_t        *blocknr,
+                                          int  blockcnt,
+                                          void *private),
+                              void *private)
+{
+       int     i;
+       int     ret = 0;
+       struct block_context ctx;
+       blk_t   blocks[EXT2_N_BLOCKS];  /* directory data blocks */
+       struct ext2_inode inode;
+       errcode_t       retval;
+       
+       ret = ext2fs_get_blocks(fs, ino, blocks);
+       if (ret)
+               return ret;
+
+       ctx.fs = fs;
+       ctx.func = func;
+       ctx.private = private;
+       ctx.bcount = 0;
+       ctx.flags = flags;
+       if (block_buf) {
+               ctx.ind_buf = block_buf;
+       } else {
+               ctx.ind_buf = malloc(fs->blocksize * 3);
+               if (!ctx.ind_buf)
+                       return ENOMEM;
+       }
+       ctx.dind_buf = ctx.ind_buf + fs->blocksize;
+       ctx.tind_buf = ctx.dind_buf + fs->blocksize;
+       
+       for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
+               if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
+                       ret |= (*func)(fs, &blocks[i], ctx.bcount, private);
+                       if (ret & BLOCK_ABORT)
+                               goto abort;
+               }
+       }
+       if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
+               ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK, &ctx);
+               if (ret & BLOCK_ABORT)
+                       goto abort;
+       }
+       if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
+               ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK, &ctx);
+               if (ret & BLOCK_ABORT)
+                       goto abort;
+       }
+       if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND))
+               ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK, &ctx);
+
+abort:
+       if (ret & BLOCK_CHANGED) {
+               retval = ext2fs_read_inode(fs, ino, &inode);
+               if (retval)
+                       return retval;
+               for (i=0; i < EXT2_N_BLOCKS; i++)
+                       inode.i_block[i] = blocks[i];
+               retval = ext2fs_write_inode(fs, ino, &inode);
+               if (retval)
+                       return retval;
+       }
+
+       if (!block_buf)
+               free(ctx.ind_buf);
+
+       return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
+}
diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c
new file mode 100644 (file)
index 0000000..d25f312
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * closefs.c --- close an ext2 filesystem
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+errcode_t ext2fs_flush(ext2_filsys fs)
+{
+       int             i,j;
+       int             group_block;
+       errcode_t       retval;
+       char            *group_ptr;
+       
+       /*
+        * Write out master superblock.  This has to be done
+        * separately, since it is located at a fixed location
+        * (SUPERBLOCK_OFFSET).
+        */
+       fs->super->s_wtime = time(NULL);
+       io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
+       retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE, fs->super);
+       if (retval)
+               return retval;
+       io_channel_set_blksize(fs->io, fs->blocksize);
+
+       /*
+        * Write out the master group descriptors, and the backup
+        * superblocks and group descriptors.
+        */
+       group_block = fs->super->s_first_data_block;
+       for (i = 0; i < fs->group_desc_count; i++) {
+               if (i !=0 ) {
+                       retval = io_channel_write_blk(fs->io, group_block,
+                                                     -SUPERBLOCK_SIZE,
+                                                     fs->super);
+                       if (retval)
+                               return retval;
+               }
+               group_ptr = (char *) fs->group_desc;
+               for (j=0; j < fs->desc_blocks; j++) {
+                       retval = io_channel_write_blk(fs->io,
+                                                     group_block+1+j, 1,
+                                                     group_ptr);
+                       if (retval)
+                               return retval;
+                       group_ptr += fs->blocksize;
+               }
+               group_block += EXT2_BLOCKS_PER_GROUP(fs->super);
+       }
+
+       /*
+        * If the write_bitmaps() function is present, call it to
+        * flush the bitmaps.  This is done this way so that a simple
+        * program that doesn't mess with the bitmaps doesn't need to
+        * drag in the bitmaps.c code.
+        */
+       if (fs->write_bitmaps) {
+               retval = fs->write_bitmaps(fs);
+               if (retval)
+                       return retval;
+       }
+               
+       return 0;
+}
+
+errcode_t ext2fs_close(ext2_filsys fs)
+{
+       errcode_t       retval;
+       
+       if (fs->flags & EXT2_FLAG_DIRTY) {
+               retval = ext2fs_flush(fs);
+               if (retval)
+                       return retval;
+       }
+       ext2fs_free(fs);
+       return 0;
+}
diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
new file mode 100644 (file)
index 0000000..1bc3f49
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * expand.c --- expand an ext2fs directory
+ * 
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+struct expand_dir_struct {
+       int     done;
+       errcode_t       err;
+};
+
+static int expand_dir_proc(ext2_filsys fs,
+                          blk_t        *blocknr,
+                          int  blockcnt,
+                          void *private)
+{
+       struct expand_dir_struct *es = (struct expand_dir_struct *) private;
+       blk_t   new_blk;
+       static blk_t    last_blk = 0;
+       char            *block;
+       errcode_t       retval;
+       int             group;
+       
+       if (*blocknr) {
+               last_blk = *blocknr;
+               return 0;
+       }
+       retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
+       if (retval) {
+               es->err = retval;
+               return BLOCK_ABORT;
+       }
+       if (blockcnt > 0) {
+               retval = ext2fs_new_dir_block(fs, 0, 0, &block);
+               if (retval) {
+                       es->err = retval;
+                       return BLOCK_ABORT;
+               }
+               es->done = 1;
+       } else {
+               block = malloc(fs->blocksize);
+               if (!block) {
+                       es->err = ENOMEM;
+                       return BLOCK_ABORT;
+               }
+               memset(block, 0, fs->blocksize);
+       }       
+       retval = io_channel_write_blk(fs->io, new_blk, 1, block);
+       if (retval) {
+               es->err = retval;
+               return BLOCK_ABORT;
+       }
+       free(block);
+       *blocknr = new_blk;
+       ext2fs_mark_block_bitmap(fs, fs->block_map, new_blk);
+       ext2fs_mark_bb_dirty(fs);
+       group = ext2fs_group_of_blk(fs, new_blk);
+       fs->group_desc[group].bg_free_blocks_count--;
+       fs->super->s_free_blocks_count--;
+       ext2fs_mark_super_dirty(fs);
+       if (es->done)
+               return (BLOCK_CHANGED | BLOCK_ABORT);
+       else
+               return BLOCK_CHANGED;
+}
+
+errcode_t ext2fs_expand_dir(ext2_filsys fs, ino_t dir)
+{
+       errcode_t       retval;
+       struct expand_dir_struct es;
+       struct ext2_inode       inode;
+       
+       if (!(fs->flags & EXT2_FLAG_RW))
+               return EXT2_ET_RO_FILSYS;
+
+       retval = ext2fs_check_directory(fs, dir);
+       if (retval)
+               return retval;
+       
+       es.done = 0;
+       es.err = 0;
+       
+       retval = ext2fs_block_iterate(fs, dir, BLOCK_FLAG_APPEND,
+                                     0, expand_dir_proc, &es);
+
+       if (es.err)
+               return es.err;
+       if (!es.done)
+               return EXT2_ET_EXPAND_DIR_ERR;
+
+       /*
+        * Update the size and block count fields in the inode.
+        */
+       retval = ext2fs_read_inode(fs, dir, &inode);
+       if (retval)
+               return retval;
+       
+       inode.i_size += fs->blocksize;
+       inode.i_blocks += fs->blocksize / 512;
+
+       retval = ext2fs_write_inode(fs, dir, &inode);
+       if (retval)
+               return retval;
+
+       return 0;
+}
diff --git a/lib/ext2fs/ext2_err.c b/lib/ext2fs/ext2_err.c
new file mode 100644 (file)
index 0000000..86bfcd3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * ext2_err.c:
+ * This file is automatically generated; please do not edit it.
+ */
+#ifdef __STDC__
+#define NOARGS void
+#else
+#define NOARGS
+#define const
+#endif
+
+static const char * const text[] = {
+               "EXT2FS Library version 0.0",
+               "Bad magic number in super-block",
+               "Can't seek to superblock",
+               "Can't read superblock",
+               "Can't write superblock",
+               "Attempt to write to filesystem opened read-only",
+               "Can't read group descriptors",
+               "Can't write group descriptors",
+               "Corrupt group descriptor: bad block for block bitmap",
+               "Corrupt group descriptor: bad block for inode bitmap",
+               "Corrupt group descriptor: bad block for inode table",
+               "Can't write an inode bitmap",
+               "Can't read an inode bitmap",
+               "Can't write an block bitmap",
+               "Can't read an block bitmap",
+               "Can't write an inode table",
+               "Can't read an inode table",
+               "Can't read next inode",
+               "Filesystem has unexpected block size",
+               "EXT2 directory corrupted",
+               "Attempt to read block from filesystem resulted in short read",
+               "Attempt to write block from filesystem resulted in short write",
+               "No free space in the directory",
+               "Inode bitmap not loaded",
+               "BLOCK bitmap not loaded",
+               "Illegal inode number",
+               "Illegal block number",
+               "Internal error in ext2fs_expand_dir",
+               "Not enough space to build proposed filesystem",
+    0
+};
+
+struct error_table {
+    char const * const * msgs;
+    long base;
+    int n_msgs;
+};
+struct et_list {
+    struct et_list *next;
+    const struct error_table * table;
+};
+extern struct et_list *_et_list;
+
+static const struct error_table et = { text, 2133571328L, 29 };
+
+static struct et_list link = { 0, 0 };
+
+void initialize_ext2_error_table (NOARGS);
+
+void initialize_ext2_error_table (NOARGS) {
+    if (!link.table) {
+        link.next = _et_list;
+        link.table = &et;
+        _et_list = &link;
+    }
+}
diff --git a/lib/ext2fs/ext2_err.et b/lib/ext2fs/ext2_err.et
new file mode 100644 (file)
index 0000000..69eacda
--- /dev/null
@@ -0,0 +1,95 @@
+#
+# Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+# under the terms of the GNU Public License.
+#
+       error_table ext2
+
+ec     EXT2_ET_BASE,
+       "EXT2FS Library version 0.0"
+
+ec     EXT2_ET_BAD_MAGIC,
+       "Bad magic number in super-block"
+
+ec     EXT2_ET_SB_LSEEK,
+       "Can't seek to superblock"
+
+ec     EXT2_ET_SB_READ,
+       "Can't read superblock"
+
+ec     EXT2_ET_SB_WRITE,
+       "Can't write superblock"
+
+ec     EXT2_ET_RO_FILSYS,
+       "Attempt to write to filesystem opened read-only"
+
+ec     EXT2_ET_GDESC_READ,
+       "Can't read group descriptors"
+
+ec     EXT2_ET_GDESC_WRITE,
+       "Can't write group descriptors"
+
+ec     EXT2_ET_GDESC_BAD_BLOCK_MAP,
+       "Corrupt group descriptor: bad block for block bitmap"
+
+ec     EXT2_ET_GDESC_BAD_INODE_MAP,
+       "Corrupt group descriptor: bad block for inode bitmap"
+
+ec     EXT2_ET_GDESC_BAD_INODE_TABLE,
+       "Corrupt group descriptor: bad block for inode table"
+
+ec     EXT2_ET_INODE_BITMAP_WRITE,
+       "Can't write an inode bitmap"
+
+ec     EXT2_ET_INODE_BITMAP_READ,
+       "Can't read an inode bitmap"
+
+ec     EXT2_ET_BLOCK_BITMAP_WRITE,
+       "Can't write an block bitmap"
+
+ec     EXT2_ET_BLOCK_BITMAP_READ,
+       "Can't read an block bitmap"
+
+ec     EXT2_ET_INODE_TABLE_WRITE,
+       "Can't write an inode table"
+
+ec     EXT2_ET_INODE_TABLE_READ,
+       "Can't read an inode table"
+
+ec     EXT2_ET_NEXT_INODE_READ,
+       "Can't read next inode"
+
+ec     EXT2_ET_UNEXPECTED_BLOCK_SIZE,
+       "Filesystem has unexpected block size"
+
+ec     EXT2_ET_DIR_CORRUPTED,
+       "EXT2 directory corrupted"
+
+ec     EXT2_ET_SHORT_READ,
+       "Attempt to read block from filesystem resulted in short read"
+
+ec     EXT2_ET_SHORT_WRITE,
+       "Attempt to write block from filesystem resulted in short write"
+
+ec     EXT2_ET_DIR_NO_SPACE,
+       "No free space in the directory"
+
+ec     EXT2_ET_NO_INODE_BITMAP,
+       "Inode bitmap not loaded"
+
+ec     EXT2_ET_NO_BLOCK_BITMAP,
+       "BLOCK bitmap not loaded"
+
+ec     EXT2_ET_BAD_INODE_NUM,
+       "Illegal inode number"
+
+ec     EXT2_ET_BAD_BLOCK_NUM,
+       "Illegal block number"
+
+ec     EXT2_ET_EXPAND_DIR_ERR,
+       "Internal error in ext2fs_expand_dir"
+
+ec     EXT2_ET_TOOSMALL,
+       "Not enough space to build proposed filesystem"
+
+       end
+
diff --git a/lib/ext2fs/ext2_err.h b/lib/ext2fs/ext2_err.h
new file mode 100644 (file)
index 0000000..1e72ced
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * ext2_err.h:
+ * This file is automatically generated; please do not edit it.
+ */
+#ifdef __STDC__
+#define NOARGS void
+#else
+#define NOARGS
+#define const
+#endif
+
+#define EXT2_ET_BASE                             (2133571328L)
+#define EXT2_ET_BAD_MAGIC                        (2133571329L)
+#define EXT2_ET_SB_LSEEK                         (2133571330L)
+#define EXT2_ET_SB_READ                          (2133571331L)
+#define EXT2_ET_SB_WRITE                         (2133571332L)
+#define EXT2_ET_RO_FILSYS                        (2133571333L)
+#define EXT2_ET_GDESC_READ                       (2133571334L)
+#define EXT2_ET_GDESC_WRITE                      (2133571335L)
+#define EXT2_ET_GDESC_BAD_BLOCK_MAP              (2133571336L)
+#define EXT2_ET_GDESC_BAD_INODE_MAP              (2133571337L)
+#define EXT2_ET_GDESC_BAD_INODE_TABLE            (2133571338L)
+#define EXT2_ET_INODE_BITMAP_WRITE               (2133571339L)
+#define EXT2_ET_INODE_BITMAP_READ                (2133571340L)
+#define EXT2_ET_BLOCK_BITMAP_WRITE               (2133571341L)
+#define EXT2_ET_BLOCK_BITMAP_READ                (2133571342L)
+#define EXT2_ET_INODE_TABLE_WRITE                (2133571343L)
+#define EXT2_ET_INODE_TABLE_READ                 (2133571344L)
+#define EXT2_ET_NEXT_INODE_READ                  (2133571345L)
+#define EXT2_ET_UNEXPECTED_BLOCK_SIZE            (2133571346L)
+#define EXT2_ET_DIR_CORRUPTED                    (2133571347L)
+#define EXT2_ET_SHORT_READ                       (2133571348L)
+#define EXT2_ET_SHORT_WRITE                      (2133571349L)
+#define EXT2_ET_DIR_NO_SPACE                     (2133571350L)
+#define EXT2_ET_NO_INODE_BITMAP                  (2133571351L)
+#define EXT2_ET_NO_BLOCK_BITMAP                  (2133571352L)
+#define EXT2_ET_BAD_INODE_NUM                    (2133571353L)
+#define EXT2_ET_BAD_BLOCK_NUM                    (2133571354L)
+#define EXT2_ET_EXPAND_DIR_ERR                   (2133571355L)
+#define EXT2_ET_TOOSMALL                         (2133571356L)
+extern void initialize_ext2_error_table (NOARGS);
+#define ERROR_TABLE_BASE_ext2 (2133571328L)
+
+/* for compatibility with older versions... */
+#define init_ext2_err_tbl initialize_ext2_error_table
+#define ext2_err_base ERROR_TABLE_BASE_ext2
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
new file mode 100644 (file)
index 0000000..998527a
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * ext2fs.h --- ext2fs
+ * 
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+/*
+ * Where the master copy of the superblock is located, and how big
+ * superblocks are supposed to be.  We define SUPERBLOCK_SIZE because
+ * the size of the superblock structure is not necessarily trustworthy
+ * (some versions have the padding set up so that the superblock is
+ * 1032 bytes long).
+ */
+#define SUPERBLOCK_OFFSET      1024
+#define SUPERBLOCK_SIZE        1024
+
+typedef unsigned long  blk_t;
+typedef unsigned int   dgrp_t;
+
+#include "et/com_err.h"
+#include "ext2fs/io.h"
+#include "ext2fs/ext2_err.h"
+
+/*
+ * Flags for the ext2_filsys structure
+ */
+
+#define EXT2_FLAG_RW           0x01
+#define EXT2_FLAG_CHANGED      0x02
+#define EXT2_FLAG_DIRTY                0x04
+#define EXT2_FLAG_VALID                0x08
+#define EXT2_FLAG_IB_DIRTY     0x10
+#define EXT2_FLAG_BB_DIRTY     0x20
+
+typedef struct struct_ext2_filsys *ext2_filsys;
+
+struct struct_ext2_filsys {
+       io_channel                      io;
+       int                             flags;
+       char *                          device_name;
+       struct ext2_super_block *       super;
+       int                             blocksize;
+       int                             fragsize;
+       unsigned long                   group_desc_count;
+       unsigned long                   desc_blocks;
+       struct ext2_group_desc *        group_desc;
+       int                             inode_blocks_per_group;
+       char *                          inode_map;
+       char *                          block_map;
+       errcode_t (*get_blocks)(ext2_filsys fs, ino_t ino, blk_t *blocks);
+       errcode_t (*check_directory)(ext2_filsys fs, ino_t ino);
+       errcode_t (*write_bitmaps)(ext2_filsys fs);
+
+       /*
+        * Not used by ext2fs library; reserved for the use of the
+        * calling application.
+        */
+       void *                          private; 
+};
+
+/*
+ * badblocks list definitions
+ */
+
+typedef struct struct_badblocks_list *badblocks_list;
+
+struct struct_badblocks_list {
+       int     num;
+       int     size;
+       blk_t   *list;
+       int     badblocks_flags;
+};
+
+#define BADBLOCKS_FLAG_DIRTY   1
+
+typedef struct struct_badblocks_iterate *badblocks_iterate;
+
+struct struct_badblocks_iterate {
+       badblocks_list  bb;
+       int             ptr;
+};
+       
+#include "ext2fs/bitops.h"
+
+/*
+ * Return flags for the block iterator functions
+ */
+#define BLOCK_CHANGED  1
+#define BLOCK_ABORT    2
+#define BLOCK_ERROR    4
+
+/*
+ * Block interate flags
+ */
+#define BLOCK_FLAG_APPEND      1
+#define BLOCK_FLAG_DEPTH_TRAVERSE      2
+
+/*
+ * Return flags for the directory iterator functions
+ */
+#define DIRENT_CHANGED 1
+#define DIRENT_ABORT   2
+#define DIRENT_ERROR   3
+
+/*
+ * Directory iterator flags
+ */
+
+#define DIRENT_FLAG_INCLUDE_EMPTY      1
+
+/*
+ * Inode scan definitions
+ */
+struct ext2_struct_inode_scan {
+       ext2_filsys             fs;
+       ino_t                   current_inode;
+       blk_t                   current_block;
+       dgrp_t                  current_group;
+       int                     inodes_left, blocks_left, groups_left;
+       int                     inode_buffer_blocks;
+       char *                  inode_buffer;
+       struct ext2_inode *     inode_scan_ptr;
+};
+
+typedef struct ext2_struct_inode_scan *ext2_inode_scan;
+
+/*
+ * function prototypes
+ */
+
+/* alloc.c */
+extern errcode_t ext2fs_new_inode(ext2_filsys fs, ino_t dir, int mode,
+                                 char *map, ino_t *ret);
+extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
+                                 char *map, blk_t *ret);
+extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start,
+                                       blk_t finish, int num, char *map,
+                                       blk_t *ret);
+
+/* badblocks.c */
+extern errcode_t badblocks_list_create(badblocks_list *ret, int size);
+extern void badblocks_list_free(badblocks_list bb);
+extern errcode_t badblocks_list_add(badblocks_list bb, blk_t blk);
+extern int badblocks_list_test(badblocks_list bb, blk_t blk);
+extern errcode_t badblocks_list_iterate_begin(badblocks_list bb,
+                                             badblocks_iterate *ret);
+extern int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk);
+extern void badblocks_list_iterate_end(badblocks_iterate iter);
+
+/* bb_inode.c */
+extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs,
+                                       badblocks_list bb_list);
+
+/* bitmaps.c */
+extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs);
+extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs);
+extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs);
+extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs);
+extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs, char **ret);
+extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, char **ret);
+extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs);
+extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs);
+
+/* block.c */
+extern errcode_t ext2fs_block_iterate(ext2_filsys fs,
+                                     ino_t     ino,
+                                     int       flags,
+                                     char *block_buf,
+                                     int (*func)(ext2_filsys fs,
+                                                 blk_t *blocknr,
+                                                 int   blockcnt,
+                                                 void  *private),
+                                     void *private);
+
+/* closefs.c */
+extern errcode_t ext2fs_close(ext2_filsys fs);
+extern errcode_t ext2fs_flush(ext2_filsys fs);
+
+/* expanddir.c */
+extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ino_t dir);
+
+/* freefs.c */
+extern void ext2fs_free(ext2_filsys fs);
+
+/* initialize.c */
+extern errcode_t ext2fs_initialize(const char *name, int flags,
+                                  struct ext2_super_block *param,
+                                  io_manager manager, ext2_filsys *ret_fs);
+
+/* inode.c */
+extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
+                                 ext2_inode_scan *ret_scan);
+extern void ext2fs_close_inode_scan(ext2_inode_scan scan);
+extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ino_t *ino,
+                              struct ext2_inode *inode);
+extern errcode_t ext2fs_read_inode (ext2_filsys fs, unsigned long ino,
+                           struct ext2_inode * inode);
+extern errcode_t ext2fs_write_inode(ext2_filsys fs, unsigned long ino,
+                           struct ext2_inode * inode);
+extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks);
+extern errcode_t ext2fs_check_directory(ext2_filsys fs, ino_t ino);
+
+/* namei.c */
+extern errcode_t ext2fs_dir_iterate(ext2_filsys fs, 
+                             ino_t dir,
+                             int flags,
+                             char *block_buf,
+                             int (*func)(struct ext2_dir_entry *dirent,
+                                         int   offset,
+                                         int   blocksize,
+                                         char  *buf,
+                                         void  *private),
+                             void *private);
+extern errcode_t ext2fs_lookup(ext2_filsys fs, ino_t dir, const char *name,
+                        int namelen, char *buf, ino_t *inode);
+extern errcode_t ext2fs_namei(ext2_filsys fs, ino_t root, ino_t cwd,
+                       const char *name, ino_t *inode);
+
+/* newdir.c */
+extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ino_t dir_ino,
+                               ino_t parent_ino, char **block);
+
+/* mkdir.c */
+extern errcode_t ext2fs_mkdir(ext2_filsys fs, ino_t parent, ino_t inum,
+                             const char *name);
+
+/* openfs.c */
+extern errcode_t ext2fs_open(const char *name, int flags, int superblock,
+                            int block_size, io_manager manager,
+                            ext2_filsys *ret_fs);
+extern errcode_t ext2fs_check_desc(ext2_filsys fs);
+
+/* get_pathname.c */
+extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ino_t dir, ino_t ino,
+                              char **name);
+
+/* link.c */
+errcode_t ext2fs_link(ext2_filsys fs, ino_t dir, const char *name,
+                     ino_t ino, int flags);
+errcode_t ext2fs_unlink(ext2_filsys fs, ino_t dir, const char *name,
+                       ino_t ino, int flags);
+
+/* read_bb.c */
+extern errcode_t ext2fs_read_bb_inode(ext2_filsys fs, badblocks_list *bb_list);
+
+/* read_bb_file.c */
+extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, 
+                                    badblocks_list *bb_list,
+                                    void (*invalid)(ext2_filsys fs,
+                                                    blk_t blk));
+
+/* inline functions */
+extern void ext2fs_mark_super_dirty(ext2_filsys fs);
+extern void ext2fs_mark_changed(ext2_filsys fs);
+extern int ext2fs_test_changed(ext2_filsys fs);
+extern void ext2fs_mark_valid(ext2_filsys fs);
+extern void ext2fs_unmark_valid(ext2_filsys fs);
+extern int ext2fs_test_valid(ext2_filsys fs);
+extern void ext2fs_mark_ib_dirty(ext2_filsys fs);
+extern void ext2fs_mark_bb_dirty(ext2_filsys fs);
+extern int ext2fs_test_ib_dirty(ext2_filsys fs);
+extern int ext2fs_test_bb_dirty(ext2_filsys fs);
+extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk);
+extern int ext2fs_group_of_ino(ext2_filsys fs, ino_t ino);
+
+/*
+ * The actual inlined functions definitions themselves...
+ *
+ * If NO_INLINE_FUNCS is defined, then we won't try to do inline
+ * functions at all!
+ */
+#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
+#ifdef INCLUDE_INLINE_FUNCS
+#define _INLINE_ extern
+#else
+#define _INLINE_ extern __inline__
+#endif
+
+/*
+ * Mark a filesystem superblock as dirty
+ */
+_INLINE_ void ext2fs_mark_super_dirty(ext2_filsys fs)
+{
+       fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Mark a filesystem as changed
+ */
+_INLINE_ void ext2fs_mark_changed(ext2_filsys fs)
+{
+       fs->flags |= EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Check to see if a filesystem has changed
+ */
+_INLINE_ int ext2fs_test_changed(ext2_filsys fs)
+{
+       return (fs->flags & EXT2_FLAG_CHANGED);
+}
+
+/*
+ * Mark a filesystem as valid
+ */
+_INLINE_ void ext2fs_mark_valid(ext2_filsys fs)
+{
+       fs->flags |= EXT2_FLAG_VALID;
+}
+
+/*
+ * Mark a filesystem as NOT valid
+ */
+_INLINE_ void ext2fs_unmark_valid(ext2_filsys fs)
+{
+       fs->flags &= ~EXT2_FLAG_VALID;
+}
+
+/*
+ * Check to see if a filesystem is valid
+ */
+_INLINE_ int ext2fs_test_valid(ext2_filsys fs)
+{
+       return (fs->flags & EXT2_FLAG_VALID);
+}
+
+/*
+ * Mark the inode bitmap as dirty
+ */
+_INLINE_ void ext2fs_mark_ib_dirty(ext2_filsys fs)
+{
+       fs->flags |= EXT2_FLAG_IB_DIRTY | EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Mark the block bitmap as dirty
+ */
+_INLINE_ void ext2fs_mark_bb_dirty(ext2_filsys fs)
+{
+       fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Check to see if a filesystem's inode bitmap is dirty
+ */
+_INLINE_ int ext2fs_test_ib_dirty(ext2_filsys fs)
+{
+       return (fs->flags & EXT2_FLAG_IB_DIRTY);
+}
+
+/*
+ * Check to see if a filesystem's block bitmap is dirty
+ */
+_INLINE_ int ext2fs_test_bb_dirty(ext2_filsys fs)
+{
+       return (fs->flags & EXT2_FLAG_BB_DIRTY);
+}
+
+/*
+ * Return the group # of a block
+ */
+_INLINE_ int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk)
+{
+       return (blk - fs->super->s_first_data_block) /
+               fs->super->s_blocks_per_group;
+}
+
+/*
+ * Return the group # of an inode number
+ */
+_INLINE_ int ext2fs_group_of_ino(ext2_filsys fs, ino_t ino)
+{
+       return (ino - 1) / fs->super->s_inodes_per_group;
+}
+#undef _INLINE_
+#endif
+
diff --git a/lib/ext2fs/freefs.c b/lib/ext2fs/freefs.c
new file mode 100644 (file)
index 0000000..ecd169a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * freefs.c --- free an ext2 filesystem
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+void ext2fs_free(ext2_filsys fs)
+{
+       if (!fs)
+               return;
+       if (fs->io) {
+               io_channel_close(fs->io);
+       }
+       if (fs->device_name)
+               free(fs->device_name);
+       if (fs->super)
+               free(fs->super);
+       if (fs->group_desc)
+               free(fs->group_desc);
+       if (fs->block_map)
+               free(fs->block_map);
+       if (fs->inode_map)
+               free(fs->inode_map);
+       free(fs);
+}
+
diff --git a/lib/ext2fs/get_pathname.c b/lib/ext2fs/get_pathname.c
new file mode 100644 (file)
index 0000000..591af6d
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * get_pathname.c --- do directry/inode -> name translation
+ * 
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+struct get_pathname_struct {
+       int             search_ino;
+       int             parent;
+       char            *name;
+       errcode_t       errcode;
+};
+
+static int get_pathname_proc(struct ext2_dir_entry *dirent,
+                            int        offset,
+                            int        blocksize,
+                            char       *buf,
+                            void       *private)
+{
+       struct get_pathname_struct      *gp;
+
+       gp = (struct get_pathname_struct *) private;
+
+       if ((dirent->name_len == 2) &&
+           !strncmp(dirent->name, "..", 2))
+               gp->parent = dirent->inode;
+       if (dirent->inode == gp->search_ino) {
+               gp->name = malloc(dirent->name_len + 1);
+               if (!gp->name) {
+                       gp->errcode = ENOMEM;
+                       return DIRENT_ABORT;
+               }
+               strncpy(gp->name, dirent->name, dirent->name_len);
+               gp->name[dirent->name_len] = '\0';
+               return DIRENT_ABORT;
+       }
+       return 0;
+}
+
+static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ino_t dir, ino_t ino,
+                                        int maxdepth, char *buf, char **name)
+{
+       struct get_pathname_struct gp;
+       char    *parent_name, *ret;
+       errcode_t       retval;
+
+       if (dir == ino) {
+               *name = malloc(2);
+               if (!*name)
+                       return ENOMEM;
+               strcpy(*name, (dir == EXT2_ROOT_INO) ? "/" : ".");
+               return 0;
+       }
+
+       if (!dir || (maxdepth < 0)) {
+               *name = malloc(4);
+               if (!*name)
+                       return ENOMEM;
+               strcpy(*name, "...");
+               return 0;
+       }
+
+       gp.search_ino = ino;
+       gp.parent = 0;
+       gp.name = 0;
+       gp.errcode = 0;
+       
+       retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp);
+       if (retval)
+               goto cleanup;
+       if (gp.errcode) {
+               retval = gp.errcode;
+               goto cleanup;
+       }
+
+       retval = ext2fs_get_pathname_int(fs, gp.parent, dir, maxdepth-1,
+                                        buf, &parent_name);
+       if (retval)
+               goto cleanup;
+       if (!ino) {
+               *name = parent_name;
+               return 0;
+       }
+       
+       ret = malloc(strlen(parent_name)+strlen(gp.name)+2);
+       if (!ret) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+       ret[0] = 0;
+       if (parent_name[1])
+               strcat(ret, parent_name);
+       strcat(ret, "/");
+       if (gp.name)
+               strcat(ret, gp.name);
+       else
+               strcat(ret, "???");
+       *name = ret;
+       free(parent_name);
+       retval = 0;
+       
+cleanup:
+       if (gp.name)
+               free(gp.name);
+       return retval;
+}
+
+errcode_t ext2fs_get_pathname(ext2_filsys fs, ino_t dir, ino_t ino,
+                             char **name)
+{
+       char    *buf;
+       errcode_t       retval;
+
+       buf = malloc(fs->blocksize);
+       if (!buf)
+               return ENOMEM;
+       if (dir == ino)
+               ino = 0;
+       retval = ext2fs_get_pathname_int(fs, dir, ino, 32, buf, name);
+       free(buf);
+       return retval;
+       
+}
diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
new file mode 100644 (file)
index 0000000..e7e07c4
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * initialize.c --- initialize a filesystem handle given superblock
+ *     parameters.  Used by mke2fs when initializing a filesystem.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+errcode_t ext2fs_initialize(const char *name, int flags,
+                           struct ext2_super_block *param,
+                           io_manager manager, ext2_filsys *ret_fs)
+{
+       ext2_filsys     fs;
+       errcode_t       retval;
+       struct ext2_super_block *super;
+       int             frags_per_block;
+       int             rem;
+       int             overhead = 0;
+       blk_t           group_block;
+       int             i, j;
+
+       if (!param || !param->s_blocks_count)
+               return EINVAL;
+       
+       fs = (ext2_filsys) malloc(sizeof(struct struct_ext2_filsys));
+       if (!fs)
+               return ENOMEM;
+       
+       memset(fs, 0, sizeof(struct struct_ext2_filsys));
+       fs->flags = flags | EXT2_FLAG_RW;
+       retval = manager->open(name, IO_FLAG_RW, &fs->io);
+       if (retval)
+               goto cleanup;
+       fs->device_name = malloc(strlen(name)+1);
+       if (!fs->device_name) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+       strcpy(fs->device_name, name);
+       fs->super = super = malloc(SUPERBLOCK_SIZE);
+       if (!super) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+       memset(super, 0, SUPERBLOCK_SIZE);
+
+#define set_field(field, default) (super->field = param->field ? \
+                                  param->field : (default))
+
+       super->s_magic = EXT2_SUPER_MAGIC;
+       super->s_state = EXT2_VALID_FS;
+
+       set_field(s_log_block_size, 0); /* default blocksize: 1024 bytes */
+       set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */
+       set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
+       set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
+       set_field(s_errors, EXT2_ERRORS_DEFAULT);
+
+       set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
+       super->s_lastcheck = time(NULL);
+
+       fs->blocksize = EXT2_BLOCK_SIZE(super);
+       fs->fragsize = EXT2_FRAG_SIZE(super);
+       frags_per_block = fs->blocksize / fs->fragsize;
+       
+       set_field(s_blocks_per_group, 8192); /* default: 8192 blocks/group */
+       super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;
+       
+       super->s_blocks_count = param->s_blocks_count;
+
+retry:
+       set_field(s_r_blocks_count, super->s_blocks_count/20); /* 5% default */
+                 
+       fs->group_desc_count = (super->s_blocks_count -
+                               super->s_first_data_block +
+                               EXT2_BLOCKS_PER_GROUP(super) - 1)
+               / EXT2_BLOCKS_PER_GROUP(super);
+       fs->desc_blocks = (fs->group_desc_count +
+                          EXT2_DESC_PER_BLOCK(super) - 1)
+               / EXT2_DESC_PER_BLOCK(super);
+
+       set_field(s_inodes_count, (super->s_blocks_count*fs->blocksize)/4096);
+
+       /*
+        * There should be at least as many inodes as the user
+        * requested.  Figure out how many inodes per group that
+        * should be.
+        */
+       super->s_inodes_per_group = (super->s_inodes_count +
+                                    fs->group_desc_count - 1) /
+                                            fs->group_desc_count;
+       
+       /*
+        * Make sure the number of inodes per group completely fills
+        * the inode table blocks in the descriptor.  If not, add some
+        * additional inodes/group.  Waste not, want not...
+        */
+       fs->inode_blocks_per_group = (super->s_inodes_per_group +
+                                     EXT2_INODES_PER_BLOCK(super) - 1) /
+                                             EXT2_INODES_PER_BLOCK(super);
+       super->s_inodes_per_group = fs->inode_blocks_per_group *
+               EXT2_INODES_PER_BLOCK(super);
+               
+       /*
+        * adjust inode count to reflect the adjusted inodes_per_group
+        */
+       super->s_inodes_count = super->s_inodes_per_group *
+               fs->group_desc_count;
+       super->s_free_inodes_count = super->s_inodes_count;
+
+       /*
+        * Overhead is the number of bookkeeping blocks per group.  It
+        * includes the superblock backup, the group descriptor
+        * backups, the inode bitmap, the block bitmap, and the inode
+        * table.
+        */
+       overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
+       super->s_free_blocks_count = super->s_blocks_count -
+               super->s_first_data_block - (overhead*fs->group_desc_count);
+       
+       /*
+        * See if the last group is big enough to support the
+        * necessary data structures.  If not, we need to get rid of
+        * it.
+        */
+       rem = (super->s_blocks_count - super->s_first_data_block) %
+               super->s_blocks_per_group;
+       if ((fs->group_desc_count == 1) && rem && (rem < overhead))
+               return EXT2_ET_TOOSMALL;
+       if (rem && (rem < overhead+50)) {
+               super->s_blocks_count -= rem;
+               goto retry;
+       }
+
+       /*
+        * At this point we know how big the filesystem will be.  So
+        * we can do any and all allocations that depend on the block
+        * count.
+        */
+
+       retval = ext2fs_allocate_block_bitmap(fs, &fs->block_map);
+       if (retval)
+               goto cleanup;
+       
+       retval = ext2fs_allocate_inode_bitmap(fs, &fs->inode_map);
+       if (retval)
+               goto cleanup;
+
+       fs->group_desc = malloc(fs->desc_blocks * fs->blocksize);
+       if (!fs->group_desc) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+       memset(fs->group_desc, 0, fs->desc_blocks * fs->blocksize);
+
+       group_block = super->s_first_data_block;
+       for (i = 0; i < fs->group_desc_count; i++) {
+               for (j=0; j < fs->desc_blocks+1; j++)
+                       ext2fs_mark_block_bitmap(fs, fs->block_map,
+                                                group_block + j);
+               group_block += super->s_blocks_per_group;
+       }
+       
+       ext2fs_mark_super_dirty(fs);
+       ext2fs_mark_bb_dirty(fs);
+       ext2fs_mark_ib_dirty(fs);
+       
+       io_channel_set_blksize(fs->io, fs->blocksize);
+
+       *ret_fs = fs;
+       return 0;
+cleanup:
+       ext2fs_free(fs);
+       return retval;
+}
+       
+
+
diff --git a/lib/ext2fs/inline.c b/lib/ext2fs/inline.c
new file mode 100644 (file)
index 0000000..6ec7387
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * inline.c --- Includes the inlined functions defined in the header
+ *     files as standalone functions, in case the application program
+ *     is compiled with inlining turned off.
+ * 
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#define INCLUDE_INLINE_FUNCS
+
+#include "ext2fs.h"
+
diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
new file mode 100644 (file)
index 0000000..ba3cee8
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * inode.c --- utility routines to read and write inodes
+ * 
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
+                                ext2_inode_scan *ret_scan)
+{
+       ext2_inode_scan scan;
+
+       scan = (ext2_inode_scan) malloc(sizeof(struct ext2_struct_inode_scan));
+       if (!scan)
+               return ENOMEM;
+       memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
+
+       scan->fs = fs;
+       scan->current_group = -1;
+       scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
+       scan->groups_left = fs->group_desc_count;
+       scan->inode_buffer = malloc(scan->inode_buffer_blocks * fs->blocksize);
+       if (!scan->inode_buffer) {
+               free(scan);
+               return ENOMEM;
+       }
+       *ret_scan = scan;
+       return 0;
+}
+
+void ext2fs_close_inode_scan(ext2_inode_scan scan)
+{
+       free(scan->inode_buffer);
+       scan->inode_buffer = NULL;
+       free(scan);
+       return;
+}
+
+errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ino_t *ino,
+                               struct ext2_inode *inode)
+{
+       errcode_t       retval;
+       int             num_blocks;
+       
+       if (!scan->inode_buffer)
+               return EINVAL;
+       
+       if (scan->inodes_left <= 0) {
+               if (scan->blocks_left <= 0) {
+                       if (scan->groups_left <= 0) {
+                               *ino = 0;
+                               return 0;
+                       }
+                       scan->current_group++;
+                       scan->groups_left--;
+                       
+                       scan->current_block = scan->fs->group_desc[scan->current_group].bg_inode_table;
+                       scan->blocks_left = (EXT2_INODES_PER_GROUP(scan->fs->super) /
+                                            EXT2_INODES_PER_BLOCK(scan->fs->super));
+               } else {
+                       scan->current_block += scan->inode_buffer_blocks;
+               }
+               scan->blocks_left -= scan->inode_buffer_blocks;
+               num_blocks = scan->inode_buffer_blocks;
+               if (scan->blocks_left < 0)
+                       num_blocks += scan->blocks_left;
+               
+               scan->inodes_left = EXT2_INODES_PER_BLOCK(scan->fs->super) *
+                       num_blocks;
+
+               retval = io_channel_read_blk(scan->fs->io, scan->current_block,
+                                            num_blocks, scan->inode_buffer);
+               if (retval)
+                       return EXT2_ET_NEXT_INODE_READ;
+               scan->inode_scan_ptr = (struct ext2_inode *) scan->inode_buffer;
+       }
+       *inode = *scan->inode_scan_ptr++;
+       scan->inodes_left--;
+       scan->current_inode++;
+       *ino = scan->current_inode;
+       return 0;
+}
+
+/*
+ * Functions to read and write a single inode.
+ */
+static char *inode_buffer = 0;
+static blk_t inode_buffer_block;
+static int inode_buffer_size = 0;
+
+errcode_t ext2fs_read_inode (ext2_filsys fs, unsigned long ino,
+                            struct ext2_inode * inode)
+{
+       unsigned long group;
+       unsigned long block;
+       unsigned long block_nr;
+       errcode_t       retval;
+       int i;
+
+       if (ino > fs->super->s_inodes_count)
+               return EXT2_ET_BAD_INODE_NUM;
+       if (inode_buffer_size != fs->blocksize) {
+               if (inode_buffer)
+                       free(inode_buffer);
+               inode_buffer_size = 0;
+               inode_buffer = malloc(fs->blocksize);
+               if (!inode_buffer)
+                       return ENOMEM;
+               inode_buffer_size = fs->blocksize;
+               inode_buffer_block = 0;
+       }
+               
+       group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
+       block = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) /
+               EXT2_INODES_PER_BLOCK(fs->super);
+       i = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) %
+               EXT2_INODES_PER_BLOCK(fs->super);
+       block_nr = fs->group_desc[group].bg_inode_table + block;
+       if (block_nr != inode_buffer_block) {
+               retval = io_channel_read_blk(fs->io, block_nr, 1,
+                                            inode_buffer);
+               if (retval)
+                       return retval;
+               inode_buffer_block = block_nr;
+       }
+       memcpy (inode, (struct ext2_inode *) inode_buffer + i,
+               sizeof (struct ext2_inode));
+       return 0;
+}
+
+errcode_t ext2fs_write_inode(ext2_filsys fs, unsigned long ino,
+                    struct ext2_inode * inode)
+{
+       unsigned long group;
+       unsigned long block;
+       unsigned long block_nr;
+       errcode_t       retval;
+       int i;
+
+       if (!(fs->flags & EXT2_FLAG_RW))
+               return EXT2_ET_RO_FILSYS;
+
+       if (ino > fs->super->s_inodes_count)
+               return EXT2_ET_BAD_INODE_NUM;
+
+       if (inode_buffer_size != fs->blocksize) {
+               if (inode_buffer)
+                       free(inode_buffer);
+               inode_buffer_size = 0;
+               inode_buffer = malloc(fs->blocksize);
+               if (!inode_buffer)
+                       return ENOMEM;
+               inode_buffer_size = fs->blocksize;
+               inode_buffer_block = 0;
+       }
+               
+       group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
+       block = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) /
+               EXT2_INODES_PER_BLOCK(fs->super);
+       i = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) %
+               EXT2_INODES_PER_BLOCK(fs->super);
+       block_nr = fs->group_desc[group].bg_inode_table + block;
+       if (inode_buffer_block != block_nr) {
+               retval = io_channel_read_blk(fs->io, block_nr, 1,
+                                            inode_buffer);
+               if (retval)
+                       return retval;
+               inode_buffer_block = block_nr;
+       }
+       memcpy ((struct ext2_inode *) inode_buffer + i, inode,
+               sizeof (struct ext2_inode));
+       retval = io_channel_write_blk(fs->io, block_nr, 1, inode_buffer);
+       if (retval)
+               return retval;
+       fs->flags |= EXT2_FLAG_CHANGED;
+       return 0;
+}
+
+errcode_t ext2fs_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
+{
+       struct ext2_inode       inode;
+       int                     i;
+       errcode_t               retval;
+       
+       if (ino > fs->super->s_inodes_count)
+               return EXT2_ET_BAD_INODE_NUM;
+
+       if (fs->get_blocks) {
+               if (!(*fs->get_blocks)(fs, ino, blocks))
+                       return 0;
+       }
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval)
+               return retval;
+       for (i=0; i < EXT2_N_BLOCKS; i++)
+               blocks[i] = inode.i_block[i];
+       return 0;
+}
+
+errcode_t ext2fs_check_directory(ext2_filsys fs, ino_t ino)
+{
+       struct  ext2_inode      inode;
+       errcode_t               retval;
+       
+       if (ino > fs->super->s_inodes_count)
+               return EXT2_ET_BAD_INODE_NUM;
+
+       if (fs->check_directory)
+               return (fs->check_directory)(fs, ino);
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval)
+               return retval;
+       if (!S_ISDIR(inode.i_mode))
+               return ENOTDIR;
+       return 0;
+}
+
+       
+
diff --git a/lib/ext2fs/io.h b/lib/ext2fs/io.h
new file mode 100644 (file)
index 0000000..fd054f8
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * io.h --- the I/O manager abstraction
+ * 
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+typedef struct struct_io_manager *io_manager;
+typedef struct struct_io_channel *io_channel;
+
+struct struct_io_channel {
+       io_manager      manager;
+       char            *name;
+       int             block_size;
+       errcode_t       (*read_error)(io_channel channel,
+                                     unsigned long block,
+                                     int count,
+                                     void *data,
+                                     size_t size,
+                                     int actual_bytes_read,
+                                     errcode_t error);
+       errcode_t       (*write_error)(io_channel channel,
+                                      unsigned long block,
+                                      int count,
+                                      const void *data,
+                                      size_t size,
+                                      int actual_bytes_written,
+                                      errcode_t error);
+       void            *private_data;
+};
+
+struct struct_io_manager {
+       const char *name;
+       errcode_t (*open)(const char *name, int flags, io_channel *channel);
+       errcode_t (*close)(io_channel channel);
+       errcode_t (*set_blksize)(io_channel channel, int blksize);
+       errcode_t (*read_blk)(io_channel channel, unsigned long block,
+                             int count, void *data);
+       errcode_t (*write_blk)(io_channel channel, unsigned long block,
+                              int count, const void *data);
+       errcode_t (*flush)(io_channel channel);
+};
+
+#define IO_FLAG_RW     1
+
+/*
+ * Convenience functions....
+ */
+#define io_channel_close(c)            ((c)->manager->close((c)))
+#define io_channel_set_blksize(c,s)    ((c)->manager->set_blksize((c),s))
+#define io_channel_read_blk(c,b,n,d)   ((c)->manager->read_blk((c),b,n,d))
+#define io_channel_write_blk(c,b,n,d)  ((c)->manager->write_blk((c),b,n,d))
+#define io_channel_flush(c)            ((c)->manager->flush((c)))
+       
+extern io_manager unix_io_manager;
+
+
+
+
diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
new file mode 100644 (file)
index 0000000..f0dbbc5
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * link.c --- create or delete links in a ext2fs directory
+ * 
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+struct link_struct  {
+       const char      *name;
+       int             namelen;
+       ino_t           inode;
+       int             flags;
+       int             done;
+};     
+
+static int link_proc(struct ext2_dir_entry *dirent,
+                    int        offset,
+                    int        blocksize,
+                    char       *buf,
+                    void       *private)
+{
+       struct link_struct *ls = (struct link_struct *) private;
+       struct ext2_dir_entry *next;
+       int rec_len;
+       int ret = 0;
+
+       rec_len = EXT2_DIR_REC_LEN(ls->namelen);
+
+       /*
+        * See if the following directory entry (if any) is unused;
+        * if so, absorb it into this one.
+        */
+       next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len);
+       if ((offset + dirent->rec_len < blocksize - 8) &&
+           (next->inode == 0) &&
+           (offset + dirent->rec_len + next->rec_len <= blocksize)) {
+               dirent->rec_len += next->rec_len;
+               ret = DIRENT_CHANGED;
+       }
+
+       /*
+        * If the directory entry is used, see if we can split the
+        * directory entry to make room for the new name.  If so,
+        * truncate it and return.
+        */
+       if (dirent->inode) {
+               if (dirent->rec_len < (EXT2_DIR_REC_LEN(dirent->name_len) +
+                                      rec_len))
+                       return ret;
+               rec_len = dirent->rec_len - EXT2_DIR_REC_LEN(dirent->name_len);
+               dirent->rec_len = EXT2_DIR_REC_LEN(dirent->name_len);
+               next = (struct ext2_dir_entry *) (buf + offset +
+                                                 dirent->rec_len);
+               next->inode = 0;
+               next->name_len = 0;
+               next->rec_len = rec_len;
+               return DIRENT_CHANGED;
+       }
+
+       /*
+        * If we get this far, then the directory entry is not used.
+        * See if we can fit the request entry in.  If so, do it.
+        */
+       if (dirent->rec_len < rec_len)
+               return ret;
+       dirent->inode = ls->inode;
+       dirent->name_len = ls->namelen;
+       strncpy(dirent->name, ls->name, ls->namelen);
+
+       ls->done++;
+       return DIRENT_ABORT|DIRENT_CHANGED;
+}
+
+errcode_t ext2fs_link(ext2_filsys fs, ino_t dir, const char *name, ino_t ino,
+                     int flags)
+{
+       errcode_t       retval;
+       struct link_struct ls;
+
+       if (!(fs->flags & EXT2_FLAG_RW))
+               return EXT2_ET_RO_FILSYS;
+
+       ls.name = name;
+       ls.namelen = name ? strlen(name) : 0;
+       ls.inode = ino;
+       ls.flags = 0;
+       ls.done = 0;
+
+       retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
+                                   0, link_proc, &ls);
+       if (retval)
+               return retval;
+
+       return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE;
+}
+
+static int unlink_proc(struct ext2_dir_entry *dirent,
+                    int        offset,
+                    int        blocksize,
+                    char       *buf,
+                    void       *private)
+{
+       struct link_struct *ls = (struct link_struct *) private;
+
+       if (ls->name && (dirent->name_len != ls->namelen))
+               return 0;
+       if (ls->name && strncmp(ls->name, dirent->name, dirent->name_len))
+               return 0;
+       if (ls->inode && (dirent->inode != ls->inode))
+               return 0;
+
+       dirent->inode = 0;
+       ls->done++;
+       return DIRENT_ABORT|DIRENT_CHANGED;
+}
+
+errcode_t ext2fs_unlink(ext2_filsys fs, ino_t dir, const char *name, ino_t ino,
+                       int flags)
+{
+       errcode_t       retval;
+       struct link_struct ls;
+
+       if (!(fs->flags & EXT2_FLAG_RW))
+               return EXT2_ET_RO_FILSYS;
+
+       ls.name = name;
+       ls.namelen = name ? strlen(name) : 0;
+       ls.inode = ino;
+       ls.flags = 0;
+       ls.done = 0;
+
+       retval = ext2fs_dir_iterate(fs, dir, 0, 0, unlink_proc, &ls);
+       if (retval)
+               return retval;
+
+       return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE;
+}
+
diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c
new file mode 100644 (file)
index 0000000..03e49d8
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * mkdir.c --- make a directory in the filesystem
+ * 
+ * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+errcode_t ext2fs_mkdir(ext2_filsys fs, ino_t parent, ino_t inum,
+                      const char *name)
+{
+       errcode_t               retval;
+       struct ext2_inode       inode;
+       ino_t                   ino = inum;
+       ino_t                   scratch_ino;
+       blk_t                   blk;
+       char                    *block = 0;
+       int                     group;
+
+       /*
+        * Allocate an inode, if necessary
+        */
+       if (!ino) {
+               retval = ext2fs_new_inode(fs, parent, S_IFDIR | 0755, 0, &ino);
+               if (retval)
+                       goto cleanup;
+       }
+
+       /*
+        * Allocate a data block for the directory
+        */
+       retval = ext2fs_new_block(fs, 0, 0, &blk);
+       if (retval)
+               goto cleanup;
+
+       /*
+        * Create a scratch template for the directory
+        */
+       retval = ext2fs_new_dir_block(fs, ino, parent, &block);
+       if (retval)
+               goto cleanup;
+
+       /*
+        * Create the inode structure....
+        */
+       memset(&inode, 0, sizeof(struct ext2_inode));
+       inode.i_mode = S_IFDIR | 0755;
+       inode.i_uid = inode.i_gid = 0;
+       inode.i_blocks = fs->blocksize / 512;
+       inode.i_block[0] = blk;
+       inode.i_links_count = 2;
+       inode.i_ctime = inode.i_atime = inode.i_mtime = time(NULL);
+       inode.i_size = fs->blocksize;
+
+       /*
+        * Write out the inode and inode data block
+        */
+       retval = io_channel_write_blk(fs->io, blk, 1, block);
+       if (retval)
+               goto cleanup;
+       retval = ext2fs_write_inode(fs, ino, &inode); 
+       if (retval)
+               goto cleanup;
+
+       /*
+        * Update parent inode's counts
+        */
+       if (parent != ino) {
+               retval = ext2fs_read_inode(fs, parent, &inode);
+               if (retval)
+                       goto cleanup;
+               inode.i_links_count++;
+               retval = ext2fs_write_inode(fs, parent, &inode);
+               if (retval)
+                       goto cleanup;
+       }
+       
+       /*
+        * Link the directory into the filesystem hierarchy
+        */
+       if (name) {
+               retval = ext2fs_lookup(fs, parent, name, strlen(name), 0,
+                                      &scratch_ino);
+               if (!retval) {
+                       retval = EEXIST;
+                       name = 0;
+                       goto cleanup;
+               }
+               if (retval != ENOENT)
+                       goto cleanup;
+               retval = ext2fs_link(fs, parent, name, ino, 0);
+               if (retval)
+                       goto cleanup;
+       }
+
+       /*
+        * Update accounting....
+        */
+       ext2fs_mark_block_bitmap(fs, fs->block_map, blk);
+       ext2fs_mark_bb_dirty(fs);
+       ext2fs_mark_inode_bitmap(fs, fs->inode_map, ino);
+       ext2fs_mark_ib_dirty(fs);
+
+       group = ext2fs_group_of_blk(fs, blk);
+       fs->group_desc[group].bg_free_blocks_count--;
+       group = ext2fs_group_of_ino(fs, ino);
+       fs->group_desc[group].bg_free_inodes_count--;
+       fs->group_desc[group].bg_used_dirs_count++;
+       fs->super->s_free_blocks_count--;
+       fs->super->s_free_inodes_count--;
+       ext2fs_mark_super_dirty(fs);
+       
+cleanup:
+       if (block)
+               free(block);
+       return retval;
+
+}
+
+
diff --git a/lib/ext2fs/namei.c b/lib/ext2fs/namei.c
new file mode 100644 (file)
index 0000000..3bb6d57
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * namei.c --- ext2fs directory lookup operations
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+struct dir_context {
+       ino_t           dir;
+       int             flags;
+       char            *buf;
+       int (*func)(struct ext2_dir_entry *dirent,
+                   int offset,
+                   int blocksize,
+                   char        *buf,
+                   void        *private);
+       void            *private;
+       errcode_t       errcode;
+};
+
+static int process_dir_block(ext2_filsys fs,
+                            blk_t      *blocknr,
+                            int        blockcnt,
+                            void       *private);
+
+errcode_t ext2fs_dir_iterate(ext2_filsys fs,
+                            ino_t dir,
+                            int flags,
+                            char *block_buf,
+                            int (*func)(struct ext2_dir_entry *dirent,
+                                        int    offset,
+                                        int    blocksize,
+                                        char   *buf,
+                                        void   *private),
+                            void *private)
+{
+       struct          dir_context     ctx;
+       errcode_t       retval;
+       
+       retval = ext2fs_check_directory(fs, dir);
+       if (retval)
+               return retval;
+       
+       ctx.dir = dir;
+       ctx.flags = flags;
+       if (block_buf)
+               ctx.buf = block_buf;
+       else {
+               ctx.buf = malloc(fs->blocksize);
+               if (!ctx.buf)
+                       return ENOMEM;
+       }
+       ctx.func = func;
+       ctx.private = private;
+       ctx.errcode = 0;
+       retval = ext2fs_block_iterate(fs, dir, 0, 0, process_dir_block, &ctx);
+       if (!block_buf)
+               free(ctx.buf);
+       if (retval)
+               return retval;
+       return ctx.errcode;
+}
+
+static int process_dir_block(ext2_filsys  fs,
+                            blk_t      *blocknr,
+                            int        blockcnt,
+                            void       *private)
+{
+       struct dir_context *ctx = (struct dir_context *) private;
+       int             offset = 0;
+       int             ret;
+       int             changed = 0;
+       int             do_abort = 0;
+       struct ext2_dir_entry *dirent;
+
+       if (blockcnt < 0)
+               return 0;
+
+       ctx->errcode = io_channel_read_blk(fs->io, *blocknr, 1, ctx->buf);
+       if (ctx->errcode)
+               return BLOCK_ABORT;
+       
+       while (offset < fs->blocksize) {
+               dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
+               if (!dirent->inode &&
+                   !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
+                       goto next;
+
+               ret = (ctx->func)(dirent, offset, fs->blocksize,
+                                 ctx->buf, ctx->private);
+               if (ret & DIRENT_CHANGED)
+                       changed++;
+               if (ret & DIRENT_ABORT) {
+                       do_abort++;
+                       break;
+               }
+next:          
+               if (((offset + dirent->rec_len) > fs->blocksize) ||
+                   (dirent->rec_len < 8) ||
+                   ((dirent->name_len+8) > dirent->rec_len)) {
+                       ctx->errcode = EXT2_ET_DIR_CORRUPTED;
+                       return BLOCK_ABORT;
+               }
+               offset += dirent->rec_len;
+       }
+
+       if (changed) {
+               ctx->errcode = io_channel_write_blk(fs->io, *blocknr, 1,
+                                                   ctx->buf);
+               if (ctx->errcode)
+                       return BLOCK_ABORT;
+       }
+       if (do_abort)
+               return BLOCK_ABORT;
+       return 0;
+}
+
+struct lookup_struct  {
+       const char      *name;
+       int             len;
+       ino_t           *inode;
+       int             found;
+};     
+
+static int lookup_proc(struct ext2_dir_entry *dirent,
+                      int      offset,
+                      int      blocksize,
+                      char     *buf,
+                      void     *private)
+{
+       struct lookup_struct *ls = (struct lookup_struct *) private;
+
+       if (ls->len != dirent->name_len)
+               return 0;
+       if (strncmp(ls->name, dirent->name, dirent->name_len))
+               return 0;
+       *ls->inode = dirent->inode;
+       ls->found++;
+       return DIRENT_ABORT;
+}
+
+
+errcode_t ext2fs_lookup(ext2_filsys fs, ino_t dir, const char *name,
+                       int namelen, char *buf, ino_t *inode)
+{
+       errcode_t       retval;
+       struct lookup_struct ls;
+
+       ls.name = name;
+       ls.len = namelen;
+       ls.inode = inode;
+       ls.found = 0;
+
+       retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls);
+       if (retval)
+               return retval;
+
+       return (ls.found) ? 0 : ENOENT;
+}
+
+errcode_t ext2fs_namei(ext2_filsys fs, ino_t root, ino_t cwd, const char *name,
+                      ino_t *inode)
+{
+       ino_t           dir = cwd;
+       char            *buf;
+       const char      *p = name, *q;
+       int             len;
+       errcode_t       retval;
+
+       buf = malloc(fs->blocksize);
+       if (!buf)
+               return ENOMEM;
+       if (*p == '/') {
+               p++;
+               dir = root;
+       }
+       while (*p) {
+               q = strchr(p, '/');
+               if (q)
+                       len = q - p;
+               else
+                       len = strlen(p);
+               if (len) {
+                       retval = ext2fs_lookup(fs, dir, p, len, buf, &dir);
+                       if (retval) {
+                               free(buf);
+                               return retval;
+                       }
+               }
+               if (q)
+                       p = q+1;
+               else
+                       break;
+       }
+       *inode = dir;
+       free(buf);
+       return 0;
+}
diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c
new file mode 100644 (file)
index 0000000..948bad9
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * newdir.c --- create a new directory block
+ * 
+ * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+/*
+ * Create new directory block
+ */
+errcode_t ext2fs_new_dir_block(ext2_filsys fs, ino_t dir_ino, ino_t parent_ino,
+                              char **block)
+{
+       char    *buf;
+       struct ext2_dir_entry *dir = NULL;
+       int     rec_len;
+
+       buf = malloc(fs->blocksize);
+       if (!buf)
+               return ENOMEM;
+       memset(buf, 0, fs->blocksize);
+       dir = (struct ext2_dir_entry *) buf;
+       dir->rec_len = fs->blocksize;
+
+       if (dir_ino) {
+               /*
+                * Set up entry for '.'
+                */
+               dir->inode = dir_ino;
+               dir->name_len = 1;
+               dir->name[0] = '.';
+               rec_len = dir->rec_len - EXT2_DIR_REC_LEN(dir->name_len);
+               dir->rec_len = EXT2_DIR_REC_LEN(dir->name_len);
+
+               /*
+                * Set up entry for '..'
+                */
+               dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
+               dir->rec_len = rec_len;
+               dir->inode = parent_ino;
+               dir->name_len = 2;
+               dir->name[0] = '.';
+               dir->name[1] = '.';
+               
+       }
+       *block = buf;
+       return 0;
+}
diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c
new file mode 100644 (file)
index 0000000..b63b7aa
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * openfs.c --- open an ext2 filesystem
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+/*
+ *  Note: if superblock is non-zero, block-size must also be non-zero.
+ *     Superblock and block_size can be zero to use the default size.
+ */
+errcode_t ext2fs_open(const char *name, int flags, int superblock,
+                     int block_size, io_manager manager, ext2_filsys *ret_fs)
+{
+       ext2_filsys     fs;
+       errcode_t       retval;
+       int             i, group_block;
+       char            *dest;
+       
+       fs = (ext2_filsys) malloc(sizeof(struct struct_ext2_filsys));
+       if (!fs)
+               return ENOMEM;
+       
+       memset(fs, 0, sizeof(struct struct_ext2_filsys));
+       fs->flags = flags;
+       retval = manager->open(name, (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0,
+                              &fs->io);
+       if (retval)
+               goto cleanup;
+       fs->device_name = malloc(strlen(name)+1);
+       if (!fs->device_name) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+       strcpy(fs->device_name, name);
+       fs->super = malloc(SUPERBLOCK_SIZE);
+       if (!fs->super) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+
+       /*
+        * If the user specifies a specific block # for the
+        * superblock, then he/she must also specify the block size!
+        * Otherwise, read the master superblock located at offset
+        * SUPERBLOCK_OFFSET from the start of the partition.
+        */
+       if (superblock) {
+               if (!block_size) {
+                       retval = EINVAL;
+                       goto cleanup;
+               }
+               io_channel_set_blksize(fs->io, block_size);
+       } else {
+               io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
+               superblock = 1;
+       }
+       retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
+                                    fs->super);
+       if (retval)
+               goto cleanup;
+       
+       if (fs->super->s_magic != EXT2_SUPER_MAGIC) {
+               retval = EXT2_ET_BAD_MAGIC;
+               goto cleanup;
+       }
+       fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
+       fs->fragsize = EXT2_FRAG_SIZE(fs->super);
+       fs->inode_blocks_per_group = (fs->super->s_inodes_per_group /
+                                     EXT2_INODES_PER_BLOCK(fs->super));
+       if (block_size) {
+               if (block_size != fs->blocksize) {
+                       retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+                       goto cleanup;
+               }
+       }
+       /*
+        * Set the blocksize to the filesystem's blocksize.
+        */
+       io_channel_set_blksize(fs->io, fs->blocksize);
+       
+       /*
+        * Read group descriptors
+        */
+       fs->group_desc_count = (fs->super->s_blocks_count -
+                               fs->super->s_first_data_block +
+                               EXT2_BLOCKS_PER_GROUP(fs->super) - 1)
+               / EXT2_BLOCKS_PER_GROUP(fs->super);
+       fs->desc_blocks = (fs->group_desc_count +
+                          EXT2_DESC_PER_BLOCK(fs->super) - 1)
+               / EXT2_DESC_PER_BLOCK(fs->super);
+       fs->group_desc = malloc(fs->desc_blocks * fs->blocksize);
+       if (!fs->group_desc) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+       group_block = fs->super->s_first_data_block + 1;
+       dest = (char *) fs->group_desc;
+       for (i=0 ; i < fs->desc_blocks; i++) {
+               retval = io_channel_read_blk(fs->io, group_block, 1, dest);
+               if (retval)
+                       goto cleanup;
+               group_block++;
+               dest += fs->blocksize;
+       }
+
+       *ret_fs = fs;
+       return 0;
+cleanup:
+       ext2fs_free(fs);
+       return retval;
+}
+
+/*
+ * This routine sanity checks the group descriptors
+ */
+errcode_t ext2fs_check_desc(ext2_filsys fs)
+{
+       int i;
+       int block = fs->super->s_first_data_block;
+       int next, inode_blocks_per_group;
+
+       inode_blocks_per_group = fs->super->s_inodes_per_group /
+               EXT2_INODES_PER_BLOCK (fs->super);
+
+       for (i = 0; i < fs->group_desc_count; i++) {
+               next = block + fs->super->s_blocks_per_group;
+               /*
+                * Check to make sure block bitmap for group is
+                * located within the group.
+                */
+               if (fs->group_desc[i].bg_block_bitmap < block ||
+                   fs->group_desc[i].bg_block_bitmap >= next)
+                       return EXT2_ET_GDESC_BAD_BLOCK_MAP;
+               /*
+                * Check to make sure inode bitmap for group is
+                * located within the group
+                */
+               if (fs->group_desc[i].bg_inode_bitmap < block ||
+                   fs->group_desc[i].bg_inode_bitmap >= next)
+                       return EXT2_ET_GDESC_BAD_INODE_MAP;
+               /*
+                * Check to make sure inode table for group is located
+                * within the group
+                */
+               if (fs->group_desc[i].bg_inode_table < block ||
+                   fs->group_desc[i].bg_inode_table+inode_blocks_per_group >=
+                   next)
+                       return EXT2_ET_GDESC_BAD_INODE_TABLE;
+               
+               block = next;
+       }
+       return 0;
+}
+
diff --git a/lib/ext2fs/read_bb.c b/lib/ext2fs/read_bb.c
new file mode 100644 (file)
index 0000000..65663a0
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * read_bb --- read the bad blocks inode
+ *
+ * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+struct read_bb_record {
+       badblocks_list  bb_list;
+       errcode_t       err;
+};
+
+/*
+ * Helper function for ext2fs_read_bb_inode()
+ */
+static int mark_bad_block(ext2_filsys fs, blk_t *block_nr,
+                            int blockcnt, void *private)
+{
+       struct read_bb_record *rb = (struct read_bb_record *) private;
+       
+       if (blockcnt < 0)
+               return 0;
+       
+       rb->err = badblocks_list_add(rb->bb_list, *block_nr);
+       if (rb->err)
+               return BLOCK_ABORT;
+       return 0;
+}
+
+/*
+ * Reads the current bad blocks from the bad blocks inode.
+ */
+errcode_t ext2fs_read_bb_inode(ext2_filsys fs, badblocks_list *bb_list)
+{
+       errcode_t       retval;
+       struct read_bb_record rb;
+       struct ext2_inode inode;
+       int     numblocks;
+
+       if (!*bb_list) {
+               retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
+               if (retval)
+                       return retval;
+               numblocks = (inode.i_blocks / (fs->blocksize / 512)) + 20;
+               retval = badblocks_list_create(bb_list, numblocks);
+               if (retval)
+                       return retval;
+       }
+
+       rb.bb_list = *bb_list;
+       rb.err = 0;
+       retval = ext2fs_block_iterate(fs, EXT2_BAD_INO, 0, 0,
+                                     mark_bad_block, &rb);
+       if (retval)
+               return retval;
+
+       return rb.err;
+}
+
+
diff --git a/lib/ext2fs/read_bb_file.c b/lib/ext2fs/read_bb_file.c
new file mode 100644 (file)
index 0000000..db7b910
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * read_bb_file.c --- read a list of bad blocks for a FILE *
+ *
+ * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+/*
+ * Reads a list of bad blocks from  a FILE *
+ */
+errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, 
+                             badblocks_list *bb_list,
+                             void (*invalid)(ext2_filsys fs, blk_t blk))
+{
+       errcode_t       retval;
+       blk_t           blockno;
+       int             count;
+
+       if (!*bb_list) {
+               retval = badblocks_list_create(bb_list, 10);
+               if (retval)
+                       return retval;
+       }
+
+       while (!feof (f)) {
+               count = fscanf (f, "%lu", &blockno);
+               if (count <= 0)
+                       break;
+               if ((blockno < fs->super->s_first_data_block) ||
+                   (blockno >= fs->super->s_blocks_count)) {
+                       if (invalid)
+                               (invalid)(fs, blockno);
+                       continue;
+               }
+               retval = badblocks_list_add(*bb_list, blockno);
+               return retval;
+       }
+       return 0;
+}
+
+
diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
new file mode 100644 (file)
index 0000000..1137870
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * unix_io.c --- This is the Unix I/O interface to the I/O manager.
+ *
+ * Implements a one-block write-through cache.
+ *
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "et/com_err.h"
+#include "ext2_err.h"
+#include "io.h"
+
+struct unix_private_data {
+       int     dev;
+       int     flags;
+       char    *buf;
+       int     buf_block_nr;
+};
+
+static errcode_t unix_open(const char *name, int flags, io_channel *channel);
+static errcode_t unix_close(io_channel channel);
+static errcode_t unix_set_blksize(io_channel channel, int blksize);
+static errcode_t unix_read_blk(io_channel channel, unsigned long block,
+                              int count, void *data);
+static errcode_t unix_write_blk(io_channel channel, unsigned long block,
+                               int count, const void *data);
+static errcode_t unix_flush(io_channel channel);
+
+struct struct_io_manager struct_unix_manager = {
+       "Unix I/O Manager",
+       unix_open,
+       unix_close,
+       unix_set_blksize,
+       unix_read_blk,
+       unix_write_blk,
+       unix_flush
+};
+
+io_manager unix_io_manager = &struct_unix_manager;
+
+static errcode_t unix_open(const char *name, int flags, io_channel *channel)
+{
+       io_channel      io = NULL;
+       struct unix_private_data *data = NULL;
+       errcode_t       retval;
+
+       io = (io_channel) malloc(sizeof(struct struct_io_channel));
+       if (!io)
+               return ENOMEM;
+       data = (struct unix_private_data *)
+               malloc(sizeof(struct unix_private_data));
+       if (!data) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+       io->manager = unix_io_manager;
+       io->name = malloc(strlen(name)+1);
+       if (!io->name) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+       strcpy(io->name, name);
+       io->private_data = data;
+
+       memset(data, 0, sizeof(struct unix_private_data));
+       io->block_size = 1024;
+       data->buf = malloc(io->block_size);
+       data->buf_block_nr = -1;
+       if (!data->buf) {
+               retval = ENOMEM;
+               goto cleanup;
+       }
+       data->dev = open(name, (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY);
+       if (data->dev < 0) {
+               retval = errno;
+               goto cleanup;
+       }
+       *channel = io;
+       return 0;
+
+cleanup:
+       if (io)
+               free(io);
+       if (data) {
+               if (data->buf)
+                       free(data->buf);
+               free(data);
+       }
+       return retval;
+}
+
+static errcode_t unix_close(io_channel channel)
+{
+       struct unix_private_data *data;
+       errcode_t       retval = 0;
+
+       data = (struct unix_private_data *) channel->private_data;
+       if (close(data->dev) < 0)
+               retval = errno;
+       if (data->buf)
+               free(data->buf);
+       if (channel->private_data)
+               free(channel->private_data);
+       if (channel->name)
+               free(channel->name);
+       free(channel);
+       return retval;
+}
+
+static errcode_t unix_set_blksize(io_channel channel, int blksize)
+{
+       struct unix_private_data *data;
+
+       data = (struct unix_private_data *) channel->private_data;
+       if (channel->block_size != blksize) {
+               channel->block_size = blksize;
+               free(data->buf);
+               data->buf = malloc(blksize);
+               if (!data->buf)
+                       return ENOMEM;
+               data->buf_block_nr = -1;
+       }
+       return 0;
+}
+
+
+static errcode_t unix_read_blk(io_channel channel, unsigned long block,
+                              int count, void *buf)
+{
+       struct unix_private_data *data;
+       errcode_t       retval;
+       size_t          size;
+       int             actual = 0;
+
+       data = (struct unix_private_data *) channel->private_data;
+
+       /*
+        * If it's in the cache, use it!
+        */
+       if ((count == 1) && (block == data->buf_block_nr)) {
+               memcpy(buf, data->buf, channel->block_size);
+               return 0;
+       }
+       size = (count < 0) ? -count : count * channel->block_size;
+       if (lseek(data->dev, block * channel->block_size, SEEK_SET) !=
+           block * channel->block_size) {
+               retval = errno;
+               goto error_out;
+       }
+       actual = read(data->dev, buf, size);
+       if (actual != size) {
+               if (actual < 0)
+                       actual = 0;
+               retval = EXT2_ET_SHORT_READ;
+               goto error_out;
+       }
+       if (count == 1) {
+               data->buf_block_nr = block;
+               memcpy(data->buf, buf, size);   /* Update the cache */
+       }
+       return 0;
+       
+error_out:
+       memset((char *) buf+actual, 0, size-actual);
+       if (channel->read_error)
+               retval = (channel->read_error)(channel, block, count, buf,
+                                              size, actual, retval);
+       return retval;
+}
+
+static errcode_t unix_write_blk(io_channel channel, unsigned long block,
+                               int count, const void *buf)
+{
+       struct unix_private_data *data;
+       size_t          size;
+       int             actual = 0;
+       errcode_t       retval;
+
+       data = (struct unix_private_data *) channel->private_data;
+
+       if (count == 1)
+               size = channel->block_size;
+       else {
+               data->buf_block_nr = -1;        /* Invalidate the cache */
+               if (count < 0)
+                       size = -count;
+               else
+                       size = count * channel->block_size;
+       } 
+               
+       if (lseek(data->dev, block * channel->block_size, SEEK_SET) !=
+           block * channel->block_size) {
+               retval = errno;
+               goto error_out;
+       }
+       
+       actual = write(data->dev, buf, size);
+       if (actual != size) {
+               retval = EXT2_ET_SHORT_WRITE;
+               goto error_out;
+       }
+
+       if ((count == 1) && (block == data->buf_block_nr))
+               memcpy(data->buf, buf, size); /* Update the cache */
+       
+       return 0;
+       
+error_out:
+       if (channel->write_error)
+               retval = (channel->write_error)(channel, block, count, buf,
+                                               size, actual, retval);
+       return retval;
+}
+
+/*
+ * Flush data buffers to disk.  Since we are currently using a
+ * write-through cache, this is a no-op.
+ */
+static errcode_t unix_flush(io_channel channel)
+{
+       return 0;
+}
+
diff --git a/lib/ss/.depend b/lib/ss/.depend
new file mode 100644 (file)
index 0000000..64a78dc
--- /dev/null
@@ -0,0 +1,69 @@
+data.o : data.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h ss_internal.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h ss.h ../ss/mit-sipb-copyright.h \
+  ../ss/ss_err.h copyright.h 
+error.o : error.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h copyright.h ../et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ss_internal.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  ss.h ../ss/mit-sipb-copyright.h ../ss/ss_err.h 
+execute_cmd.o : execute_cmd.c ss_internal.h /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h ss.h ../ss/mit-sipb-copyright.h \
+  ../ss/ss_err.h copyright.h 
+help.o : help.c /usr/include/sys/param.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/limits.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/syslimits.h /usr/include/limits.h \
+  /usr/include/features.h /usr/include/sys/cdefs.h /usr/include/posix1_lim.h /usr/include/linux/limits.h \
+  /usr/include/posix2_lim.h /usr/include/linux/param.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/sys/file.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/sys/wait.h /usr/include/gnu/types.h /usr/include/waitflags.h /usr/include/waitstatus.h \
+  /usr/include/endian.h /usr/include/bytesex.h ss_internal.h /usr/include/stdio.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  ss.h ../ss/mit-sipb-copyright.h ../ss/ss_err.h copyright.h /usr/include/sys/dir.h \
+  /usr/include/dirent.h /usr/include/linux/dirent.h 
+invocation.o : invocation.c ss_internal.h /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h ss.h ../ss/mit-sipb-copyright.h \
+  ../ss/ss_err.h copyright.h 
+list_rqs.o : list_rqs.c copyright.h ss_internal.h /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h ss.h ../ss/mit-sipb-copyright.h \
+  ../ss/ss_err.h /usr/include/signal.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/linux/signal.h /usr/include/setjmp.h /usr/include/jmp_buf.h /usr/include/i386/jmp_buf.h \
+  /usr/include/sys/wait.h /usr/include/gnu/types.h /usr/include/waitflags.h /usr/include/waitstatus.h \
+  /usr/include/endian.h /usr/include/bytesex.h 
+listen.o : listen.c copyright.h ss_internal.h /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h ss.h ../ss/mit-sipb-copyright.h \
+  ../ss/ss_err.h /usr/include/setjmp.h /usr/include/jmp_buf.h /usr/include/i386/jmp_buf.h \
+  /usr/include/signal.h /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/signal.h \
+  /usr/include/sys/param.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/limits.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/syslimits.h /usr/include/limits.h \
+  /usr/include/posix1_lim.h /usr/include/linux/limits.h /usr/include/posix2_lim.h \
+  /usr/include/linux/param.h 
+pager.o : pager.c ss_internal.h /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h ss.h ../ss/mit-sipb-copyright.h \
+  ../ss/ss_err.h copyright.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/sys/file.h /usr/include/fcntl.h /usr/include/linux/fcntl.h /usr/include/signal.h \
+  /usr/include/linux/signal.h 
+parse.o : parse.c ss_internal.h /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/string.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h ss.h ../ss/mit-sipb-copyright.h \
+  ../ss/ss_err.h copyright.h 
+prompt.o : prompt.c copyright.h /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h ss_internal.h \
+  /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h ss.h \
+  ../ss/mit-sipb-copyright.h ../ss/ss_err.h 
+request_tbl.o : request_tbl.c copyright.h ss_internal.h /usr/include/stdio.h \
+  /usr/include/features.h /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h \
+  /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h ss.h \
+  ../ss/mit-sipb-copyright.h ../ss/ss_err.h 
+requests.o : requests.c mit-sipb-copyright.h /usr/include/stdio.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/libio.h /usr/include/_G_config.h ss_internal.h \
+  /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h ss.h \
+  ../ss/mit-sipb-copyright.h ../ss/ss_err.h 
+ss_err.o : ss_err.c 
+std_rqs.o : std_rqs.c ../ss/ss.h ../ss/mit-sipb-copyright.h ../ss/ss_err.h 
+test_ss.o : test_ss.c /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/libio.h /usr/include/_G_config.h ss.h ../ss/mit-sipb-copyright.h \
+  ../ss/ss_err.h 
diff --git a/lib/ss/Makefile b/lib/ss/Makefile
new file mode 100644 (file)
index 0000000..af82f91
--- /dev/null
@@ -0,0 +1,133 @@
+include ../../MCONFIG
+
+ARCHIVE=ar r
+RANLIB=ranlib
+RM=rm -f
+MV=mv
+LN=ln -s
+TAGS=etags
+COMPILE_ET=../et/compile_et
+MK_CMDS=../ss/mk_cmds
+
+# hard coded .. is so that ss/ss_err.h works
+# hard coded ../et is so com_err.h works
+CFLAGS= -I. -I.. -I../et $(OPT)
+
+# hard coded for target install
+srcdir=        .
+
+# for the library
+
+LIB=   libss.a
+
+# with ss_err.o first, ss_err.h should get rebuilt first too.  should not
+# be relying on this, though.
+OBJS=  ss_err.o \
+       std_rqs.o \
+       invocation.o help.o \
+       execute_cmd.o listen.o parse.o error.o prompt.o \
+       request_tbl.o list_rqs.o pager.o requests.o \
+       data.o
+
+SRCS=  invocation.c help.c \
+       execute_cmd.c listen.c parse.c error.c prompt.c \
+       request_tbl.c list_rqs.c pager.c requests.c \
+       data.c  \
+       ss_err.h
+# ss_err.h here, so that make depend catches it.
+
+CODE= $(SRCS) $(MKCMDSFILES)
+
+MKCMDSOBJS=    mk_cmds.o utils.o options.o ct.tab.o cmd_tbl.lex.o
+
+MKCMDSFILES=   mk_cmds.c utils.c options.c ct.y cmd_tbl.lex.l
+
+MKCMDSCSRCS=   mk_cmds.c utils.c options.c ct.tab.c cmd_tbl.lex.c
+
+
+HFILES=        ss.h ss_internal.h copyright.h
+
+# for 'tags' and dependencies
+
+CFILES=        $(SRCS) $(MKCMDSCSRCS) test_ss.c
+
+# for building archives
+
+FILES= $(SRCS) $(MKCMDSFILES) $(HFILES) \
+       ss_err.et std_rqs.ct Makefile \
+       test_ss.c ss mit-sipb-copyright.h copyright.h
+
+#
+# stuff to build
+#
+
+all::  mk_cmds libss.a # libss_p.a lint
+
+dist:  archives
+
+install:: all
+       $(INSTALLLIB) libss.a ${DESTDIR}$(LIBDIR)/libss.a
+       $(CHMOD) 644 ${DESTDIR}$(LIBDIR)/libss.a
+       $(RANLIB) ${DESTDIR}$(LIBDIR)/libss.a
+       $(CHMOD) $(LIBMODE) ${DESTDIR}$(LIBDIR)/libss.a
+
+install:: $(HFILES) copyright.h
+       @rm -rf ${DESTDIR}$(INCLDIR)/ss
+       @mkdir ${DESTDIR}$(INCLDIR)/ss
+       for i in $(HFILES) copyright.h; do \
+               $(INSTALLINC) $(srcdir)/$$i ${DESTDIR}$(INCLDIR)/ss/$$i; \
+       done
+
+install:: copyright.h
+       $(INSTALLFILE) $(srcdir)/copyright.h ${DESTDIR}$(INCLDIR)/ss/mit-sipb-copyright.h
+
+std_rqs.c: std_rqs.ct
+       $(MK_CMDS) std_rqs.ct
+
+ss_err.c ss_err.h: ss_err.et
+       $(COMPILE_ET) ss_err.et
+
+dep depend .depend: ss_err.h
+       $(CPP) -M $(CFLAGS) *.c >.depend
+
+ct.tab.c ct.tab.h: ct.y
+       rm -f ct.tab.* y.*
+       yacc -d $(srcdir)/ct.y
+       mv -f y.tab.c ct.tab.c
+       mv -f y.tab.h ct.tab.h
+
+# install_library_target(ss,$(OBJS),$(SRCS),)
+all:: libss.a
+
+libss.a: $(OBJS)
+       $(RM) $@.bak
+       -$(MV) $@ $@.bak
+       $(ARCHIVE) $@ $(OBJS)
+       $(RANLIB) $@
+       $(RM) ../$@
+       $(LN) ss/$@ ../$@
+
+clean:
+       $(RM) libss.a mk_cmds
+       $(RM) *.o *~ \#* *.bak core 
+
+really-clean: clean
+       $(RM) .depend ss_err.h
+
+#install::
+#      $(INSTALLLIB) libss.a $(DESTDIR)$(LIBDIR)/libss.a
+#      $(CHMOD) 644 $(DESTDIR)$(LIBDIR)/libss.a
+#      $(RANLIB)    $(DESTDIR)$(LIBDIR)/libss.a
+#      $(CHMOD) 444 $(DESTDIR)$(LIBDIR)/libss.a
+## 
+
+
+libss.o:       $(OBJS)
+       $(LD) -r -s -o $@ $(OBJS)
+       $(CHMOD) -x $@
+
+mk_cmds: mk_cmds.sh
+       ./config_script mk_cmds.sh $(AWK) > mk_cmds
+       chmod +x mk_cmds
+
+include .depend
diff --git a/lib/ss/config_script b/lib/ss/config_script
new file mode 100644 (file)
index 0000000..e3de35c
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# This program takes a shell script and configures for the following
+# variables:   @DIR@
+#              @AWK@
+#              @SED@
+#
+# Usage: config_script <filename> [<awk>] [<sed>]
+#
+
+FILE=$1
+AWK=$2
+SED=$3
+
+# Grr.... not all Unix's have the dirname command
+TMP=`echo  $1 | sed -e 's;[^/]*$;;' -e 's/^$/./'`
+DIR=`cd ${TMP}; pwd`
+
+if test "${AWK}x" = "x" ; then
+       AWK=awk
+fi
+if test "${SED}x" = "x" ; then
+       SED=sed
+fi
+sed -e "s;@DIR@;${DIR};" -e "s;@AWK@;${AWK};" -e "s;@SED@;${SED};" $FILE
diff --git a/lib/ss/copyright.h b/lib/ss/copyright.h
new file mode 100644 (file)
index 0000000..e0d1572
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+
+Copyright 1987, 1989 by the Student Information Processing Board
+       of the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is
+hereby granted, provided that the above copyright notice
+appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation,
+and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+M.I.T. and the M.I.T. S.I.P.B. make no representations about
+the suitability of this software for any purpose.  It is
+provided "as is" without express or implied warranty.
+
+*/
+
diff --git a/lib/ss/ct_c.awk b/lib/ss/ct_c.awk
new file mode 100644 (file)
index 0000000..872f6e0
--- /dev/null
@@ -0,0 +1,77 @@
+/^command_table / {
+       cmdtbl = $2;
+       printf "/* %s.c - automatically generated from %s.ct */\n", \
+               rootname, rootname > outfile
+       print "#include <ss/ss.h>" > outfile
+       print "" >outfile
+       print "#ifndef __STDC__" > outfile
+       print "#define const" > outfile
+       print "#endif" > outfile
+       print "" > outfile
+}
+       
+/^BOR$/ {
+       cmdnum++
+       options = 0
+       cmdtab = ""
+       printf "static char const * const ssu%05d[] = {\n", cmdnum > outfile
+}
+
+/^sub/ {
+       subr = substr($0, 6, length($0)-5)
+}
+
+/^hlp/ {
+       help = substr($0, 6, length($0)-5)
+}
+
+/^cmd/ {
+       cmd = substr($0, 6, length($0)-5)
+       printf "%s\"%s\",\n", cmdtab, cmd > outfile
+       cmdtab = "    "
+}
+
+/^opt/ {
+       opt = substr($0, 6, length($0)-5)
+       if (opt == "dont_list") {
+               options += 1
+       }
+       if (opt == "dont_summarize") {
+               options += 2
+       }
+}
+
+/^EOR/ {
+       print "    (char const *)0" > outfile
+       print "};" > outfile 
+       printf "extern void %s __SS_PROTO;\n", subr > outfile
+       subr_tab[cmdnum] = subr
+       options_tab[cmdnum] = options
+       help_tab[cmdnum] = help
+}
+
+/^[0-9]/ {
+       linenum = $1;
+}
+
+/^ERROR/ {
+       error = substr($0, 8, length($0)-7)
+       printf "Error in line %d: %s\n", linenum, error
+       print "#__ERROR_IN_FILE__" > outfile
+}
+
+END {
+       printf "static ss_request_entry ssu%05d[] = {\n", cmdnum+1 > outfile
+       for (i=1; i <= cmdnum; i++) {
+               printf "    { ssu%05d,\n", i > outfile
+               printf "      %s,\n", subr_tab[i] > outfile
+               printf "      \"%s\",\n", help_tab[i] > outfile
+               printf "      %d },\n", options_tab[i] > outfile
+       }
+       print "    { 0, 0, 0, 0 }" > outfile
+       print "};" > outfile
+       print "" > outfile
+       printf "ss_request_table %s = { 2, ssu%05d };\n", \
+               cmdtbl, cmdnum+1 > outfile
+}
+
diff --git a/lib/ss/ct_c.sed b/lib/ss/ct_c.sed
new file mode 100644 (file)
index 0000000..8d6452b
--- /dev/null
@@ -0,0 +1,160 @@
+#
+# This script parses a command_table file into something which is a bit 
+# easier for an awk script to understand.
+#
+# Input syntax: a .ct file
+#
+# Output syntax:
+# (for the command_table line)
+#      command_table  <command_table>
+#
+#(for each request definition)
+#      BOR
+#      sub: <subroutine name>
+#      hlp: <help text>
+#      cmd: <command>
+#      opt: <option>
+#      EOR
+# (there may be more than one 'cmd' or 'opt' line
+#
+# A number sent to the output represents a parse error --- it will be 
+# followed by the next line which will have the form:
+#      ERROR: <error text>
+#
+# The design of this output syntax is such that it should be easy for
+# an awk script to parse.
+
+#
+# The first section of this script is just to cannoicalize the file.  
+# It removes comments, and puts each command_table request onto a single
+# line
+#
+:FIRST
+y/     / /
+s/^ *//
+s/#.*$//
+/; *$/!{
+N
+y/     / /
+s/\n */ /
+bFIRST
+}
+s/, */, /g
+#
+# Now we take care of some syntatic sugar.....
+#
+/^unimplemented/ {
+       s/^unimplemented [A-Za-z_0-9]*/request ss_unimplemented/
+       s/;/, (dont_list, dont_summarize);/
+}
+/^unknown/ {
+       s/^unknown /request ss_unknown, "", /
+}
+#
+# Dispatch based on the keyword....  illegal keywords are prefixed by ERROR:
+# and are handled by the awk script.
+#
+/^command_table /bCMD
+/^request /bREQUEST
+/^end;/bEND
+s/ .*//
+s/^/ERROR: unknown keyword: /
+=
+b
+#
+# Handle the command_table keyword
+#
+:CMD
+s/;$//
+p
+d
+b
+#
+# Handle the request keyword --- this is the heart of the sed script.
+# 
+:REQUEST
+s/^request *//
+h
+i\
+BOR
+# First, parse out the subroutine name
+s/^/sub: /
+s/,.*//
+p
+# Next, parse out the help message, being careful to handle a quoted string
+g
+s/^[^,]*, *//
+h
+/^"/ {
+       s/^"//
+       s/".*//
+       x
+       s/^"[^"]*", *//
+       x
+       b EMITHLP
+}
+s/[^a-zA-Z0-9].*//
+x
+s/[a-zA-Z0-9]*, *//
+x
+:EMITHLP
+s/^/hlp: /
+p
+# Next take care of the command names
+:CMDLIST
+g
+/^(/b OPTIONS
+/^;/b EOR
+/^"/ {
+       s/^"//
+       s/".*//
+       x
+       s/^"[^"]*"//
+       s/, *//
+       x
+       b EMITREQ
+}
+s/[^A-Za-z_0-9].*//
+x
+s/[A-Za-z_0-9]*//
+s/, *//
+x
+:EMITREQ
+s/^/cmd: /
+p
+b CMDLIST
+#
+# Here we parse the list of options.
+#
+: OPTIONS
+g
+s/^(//
+h
+: OPTLIST
+/^)/ b EOR
+/^[^A-Za-z_0-9]/ {
+       =
+       c\
+ERROR: parse error in options list
+}
+s/[^A-Za-z_0-9].*//
+x
+s/[A-Za-z_0-9]*//
+s/, *//
+x
+s/^/opt: /
+p
+g
+b OPTLIST
+: EOR
+c\
+EOR\
+
+d
+b
+#
+# Handle the end keyword --- it's basically ignored.
+#
+:END
+d
+b
diff --git a/lib/ss/data.c b/lib/ss/data.c
new file mode 100644 (file)
index 0000000..dd6341c
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright 1987, 1988, 1989 Massachusetts Institute of Technology
+ * (Student Information Processing Board)
+ *
+ * For copyright info, see copyright.h.
+ */
+
+#include <stdio.h>
+#include "ss_internal.h"
+#include "copyright.h"
+
+const static char copyright[] =
+    "Copyright 1987, 1988, 1989 by the Massachusetts Institute of Technology";
+
+ss_data **_ss_table = (ss_data **)NULL;
+char *_ss_pager_name = (char *)NULL;
diff --git a/lib/ss/error.c b/lib/ss/error.c
new file mode 100644 (file)
index 0000000..3b7165a
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright 1987, 1988, 1989 by MIT Student Information Processing
+ * Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include <stdio.h>
+
+/*
+ * I'm assuming that com_err.h includes varargs.h, which it does
+ * (right now).  There really ought to be a way for me to include the
+ * file without worrying about whether com_err.h includes it or not,
+ * but varargs.h doesn't define anything that I can use as a flag, and
+ * gcc will lose if I try to include it twice and redefine stuff.
+ */
+#if !defined(__STDC__) || !defined(ibm032) || !defined(NeXT)
+#define ss_error ss_error_external
+#endif
+
+#include "copyright.h"
+#include <com_err.h>
+#include "ss_internal.h"
+
+#ifdef _STDARG_H_
+#define STDARG
+#endif
+
+#ifdef _STDARG_H
+#define STDARG
+#endif
+
+#ifndef __STDC__
+/* we didn't get it in com_err.h if it wasn't STDC. */
+#ifndef STDARG
+/* and we don't need it, either, if we're using stdarg.h... */
+#include <varargs.h>
+#endif
+#endif
+  
+#undef ss_error
+
+char * ss_name(sci_idx)
+    int sci_idx;
+{
+    register char *ret_val;
+    register ss_data *infop;
+    
+    infop = ss_info(sci_idx);
+    if (infop->current_request == (char const *)NULL) {
+       ret_val = malloc((unsigned)
+                        (strlen(infop->subsystem_name)+1)
+                        * sizeof(char));
+       if (ret_val == (char *)NULL)
+           return((char *)NULL);
+       strcpy(ret_val, infop->subsystem_name);
+       return(ret_val);
+    }
+    else {
+       register char *cp;
+       register char const *cp1;
+       ret_val = malloc((unsigned)sizeof(char) * 
+                        (strlen(infop->subsystem_name)+
+                         strlen(infop->current_request)+
+                         4));
+       cp = ret_val;
+       cp1 = infop->subsystem_name;
+       while (*cp1)
+           *cp++ = *cp1++;
+       *cp++ = ' ';
+       *cp++ = '(';
+       cp1 = infop->current_request;
+       while (*cp1)
+           *cp++ = *cp1++;
+       *cp++ = ')';
+       *cp = '\0';
+       return(ret_val);
+    }
+}
+
+#ifdef STDARG
+void ss_error (int sci_idx, long code, const char * fmt, ...)
+#else
+void ss_error (va_alist)
+    va_dcl
+#endif
+{
+    register char const *whoami;
+    va_list pvar;
+#ifndef STDARG
+    int sci_idx;
+    long code;
+    char * fmt;
+    va_start (pvar);
+    sci_idx = va_arg (pvar, int);
+    code = va_arg (pvar, long);
+    fmt = va_arg (pvar, char *);
+#else
+    va_start (pvar, fmt);
+#endif
+    whoami = ss_name (sci_idx);
+    com_err_va (whoami, code, fmt, pvar);
+    free (whoami);
+    va_end(pvar);
+}
+
+void ss_perror (sci_idx, code, msg) /* for compatibility */
+    int sci_idx;
+    long code;
+    char const *msg;
+{
+    ss_error (sci_idx, code, "%s", msg);
+}
diff --git a/lib/ss/execute_cmd.c b/lib/ss/execute_cmd.c
new file mode 100644 (file)
index 0000000..9442f33
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright 1987, 1988, 1989 by Massachusetts Institute of Technology
+ *
+ * For copyright info, see copyright.h.
+ */
+
+#include "ss_internal.h"
+#include "copyright.h"
+#include <stdio.h>
+
+#ifndef lint
+static char const rcsid[] =
+    "$Header$";
+#endif
+
+/*
+ * get_request(tbl, idx)
+ *
+ * Function:
+ *      Gets the idx'th request from the request table pointed to
+ *      by tbl.
+ * Arguments:
+ *      tbl (ss_request_table *)
+ *              pointer to request table
+ *      idx (int)
+ *              index into table
+ * Returns:
+ *      (ss_request_entry *)
+ *              pointer to request table entry
+ * Notes:
+ *      Has been replaced by a macro.
+ */
+
+#ifdef __SABER__
+/* sigh.  saber won't deal with pointer-to-const-struct */
+static struct _ss_request_entry * get_request (tbl, idx)
+    ss_request_table * tbl;
+    int idx;
+{
+    struct _ss_request_table *tbl1 = (struct _ss_request_table *) tbl;
+    struct _ss_request_entry *e = (struct _ss_request_entry *) tbl1->requests;
+    return e + idx;
+}
+#else
+#define get_request(tbl,idx)    ((tbl) -> requests + (idx))
+#endif
+
+/*
+ * check_request_table(rqtbl, argc, argv, sci_idx)
+ *
+ * Function:
+ *      If the command string in argv[0] is in the request table, execute
+ *      the commands and return error code 0.  Otherwise, return error
+ *      code ss_et_command_not_found.
+ * Arguments:
+ *      rqtbl (ss_request_table *)
+ *              pointer to request table
+ *      argc (int)
+ *              number of elements in argv[]
+ *      argv (char *[])
+ *              argument string array
+ *      sci_idx (int)
+ *              ss-internal index for subsystem control info structure
+ * Returns:
+ *      (int)
+ *              zero if command found, ss_et_command_not_found otherwise
+ * Notes:
+ */
+
+static int check_request_table (rqtbl, argc, argv, sci_idx)
+    register ss_request_table *rqtbl;
+    int argc;
+    char *argv[];
+    int sci_idx;
+{
+#ifdef __SABER__
+    struct _ss_request_entry *request;
+#else
+    register ss_request_entry *request;
+#endif
+    register ss_data *info;
+    register char const * const * name;
+    char *string = argv[0];
+    int i;
+
+    info = ss_info(sci_idx);
+    info->argc = argc;
+    info->argv = argv;
+    for (i = 0; (request = get_request(rqtbl, i))->command_names; i++) {
+       for (name = request->command_names; *name; name++)
+           if (!strcmp(*name, string)) {
+               info->current_request = request->command_names[0];
+               (request->function)(argc, (const char *const *) argv,
+                                   sci_idx,info->info_ptr);
+               info->current_request = (char *)NULL;
+               return(0);
+           }
+    }
+    return(SS_ET_COMMAND_NOT_FOUND);
+}
+
+/*
+ * really_execute_command(sci_idx, argc, argv)
+ *
+ * Function:
+ *      Fills in the argc, argv values in the subsystem entry and
+ *      call the appropriate routine.
+ * Arguments:
+ *      sci_idx (int)
+ *              ss-internal index for subsystem control info structure
+ *      argc (int)
+ *              number of arguments in argument list
+ *      argv (char **[])
+ *              pointer to parsed argument list (may be reallocated
+ *              on abbrev expansion)
+ *
+ * Returns:
+ *      (int)
+ *              Zero if successful, ss_et_command_not_found otherwise.
+ * Notes:
+ */
+
+static int really_execute_command (sci_idx, argc, argv)
+    int sci_idx;
+    int argc;
+    char **argv[];
+{
+    register ss_request_table **rqtbl;
+    register ss_data *info;
+
+    info = ss_info(sci_idx);
+
+    for (rqtbl = info->rqt_tables; *rqtbl; rqtbl++) {
+        if (check_request_table (*rqtbl, argc, *argv, sci_idx) == 0)
+            return(0);
+    }
+    return(SS_ET_COMMAND_NOT_FOUND);
+}
+
+/*
+ * ss_execute_command(sci_idx, argv)
+ *
+ * Function:
+ *     Executes a parsed command list within the subsystem.
+ * Arguments:
+ *     sci_idx (int)
+ *             ss-internal index for subsystem control info structure
+ *     argv (char *[])
+ *             parsed argument list
+ * Returns:
+ *     (int)
+ *             Zero if successful, ss_et_command_not_found otherwise.
+ * Notes:
+ */
+
+ss_execute_command(sci_idx, argv)
+       int sci_idx;
+       register char *argv[];
+{
+       register int i, argc;
+       char **argp;
+
+       argc = 0;
+       for (argp = argv; *argp; argp++)
+               argc++;
+       argp = (char **)malloc((argc+1)*sizeof(char *));
+       for (i = 0; i <= argc; i++)
+               argp[i] = argv[i];
+       i = really_execute_command(sci_idx, argc, &argp);
+       free(argp);
+       return(i);
+}
+
+/*
+ * ss_execute_line(sci_idx, line_ptr)
+ *
+ * Function:
+ *      Parses and executes a command line within a subsystem.
+ * Arguments:
+ *      sci_idx (int)
+ *              ss-internal index for subsystem control info structure
+ *      line_ptr (char *)
+ *              Pointer to command line to be parsed.
+ * Returns:
+ *      (int)
+ *             Error code.
+ * Notes:
+ */
+
+int ss_execute_line (sci_idx, line_ptr)
+    int sci_idx;
+    char *line_ptr;
+{
+    char **argv;
+    int argc;
+
+    /* flush leading whitespace */
+    while (line_ptr[0] == ' ' || line_ptr[0] == '\t')
+        line_ptr++;
+
+    /* check if it should be sent to operating system for execution */
+    if (*line_ptr == '!') {
+        if (ss_info(sci_idx)->flags.escape_disabled)
+            return SS_ET_ESCAPE_DISABLED;
+        else {
+            line_ptr++;
+            system(line_ptr);
+           return 0;
+        }
+    }
+
+    /* parse it */
+    argv = ss_parse(sci_idx, line_ptr, &argc);
+    if (argc == 0)
+        return 0;
+
+    /* look it up in the request tables, execute if found */
+    return really_execute_command (sci_idx, argc, &argv);
+}
diff --git a/lib/ss/help.c b/lib/ss/help.c
new file mode 100644 (file)
index 0000000..ad3b90b
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright info, see copyright.h.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#ifdef NEED_SYS_FCNTL_H
+/* just for O_* */
+#include <sys/fcntl.h>
+#endif
+#include <sys/wait.h>
+#include "ss_internal.h"
+#include "copyright.h"
+
+extern int errno;
+
+void ss_help (argc, argv, sci_idx, info_ptr)
+    int argc;
+    char const * const *argv;
+    int sci_idx;
+    pointer info_ptr;
+{
+    char buffer[MAXPATHLEN];
+    char const *request_name;
+    int code;
+    int fd, child;
+    register int idx;
+    register ss_data *info;
+
+    request_name = ss_current_request(sci_idx, &code);
+    if (code != 0) {
+       ss_perror(sci_idx, code, "");
+       return;         /* no ss_abort_line, if invalid invocation */
+    }
+    if (argc == 1) {
+       ss_list_requests(argc, argv, sci_idx, info_ptr);
+       return;
+    }
+    else if (argc != 2) {
+       /* should do something better than this */
+       sprintf(buffer, "usage:\n\t%s [topic|command]\nor\t%s\n",
+               request_name, request_name);
+       ss_perror(sci_idx, 0, buffer);
+       return;
+    }
+    info = ss_info(sci_idx);
+    if (info->info_dirs == (char **)NULL) {
+       ss_perror(sci_idx, SS_ET_NO_INFO_DIR, (char *)NULL);
+       return;
+    }
+    if (info->info_dirs[0] == (char *)NULL) {
+       ss_perror(sci_idx, SS_ET_NO_INFO_DIR, (char *)NULL);
+       return;
+    }
+    for (idx = 0; info->info_dirs[idx] != (char *)NULL; idx++) {
+       (void) strcpy(buffer, info->info_dirs[idx]);
+       (void) strcat(buffer, "/");
+       (void) strcat(buffer, argv[1]);
+       (void) strcat(buffer, ".info");
+       if ((fd = open(&buffer[0], O_RDONLY)) >= 0) goto got_it;
+    }
+    if ((fd = open(&buffer[0], O_RDONLY)) < 0) {
+       char buf[MAXPATHLEN];
+       strcpy(buf, "No info found for ");
+       strcat(buf, argv[1]);
+       ss_perror(sci_idx, 0, buf);
+       return;
+    }
+got_it:
+    switch (child = fork()) {
+    case -1:
+       ss_perror(sci_idx, errno, "Can't fork for pager");
+       return;
+    case 0:
+       (void) dup2(fd, 0); /* put file on stdin */
+       ss_page_stdin();
+    default:
+       (void) close(fd); /* what can we do if it fails? */
+       while (wait((union wait *)NULL) != child) {
+           /* do nothing if wrong pid */
+       };
+    }
+}
+
+#ifndef USE_DIRENT_H
+#include <sys/dir.h>
+#else
+#include <dirent.h>
+#endif
+
+void ss_add_info_dir(sci_idx, info_dir, code_ptr)
+    int sci_idx;
+    char *info_dir;
+    int *code_ptr;
+{
+    register ss_data *info;
+    DIR *d;
+    int n_dirs;
+    register char **dirs;
+
+    info = ss_info(sci_idx);
+    if (info_dir == NULL && *info_dir) {
+       *code_ptr = SS_ET_NO_INFO_DIR;
+       return;
+    }
+    if ((d = opendir(info_dir)) == (DIR *)NULL) {
+       *code_ptr = errno;
+       return;
+    }
+    closedir(d);
+    dirs = info->info_dirs;
+    for (n_dirs = 0; dirs[n_dirs] != (char *)NULL; n_dirs++)
+       ;               /* get number of non-NULL dir entries */
+    dirs = (char **)realloc((char *)dirs,
+                           (unsigned)(n_dirs + 2)*sizeof(char *));
+    if (dirs == (char **)NULL) {
+       info->info_dirs = (char **)NULL;
+       *code_ptr = errno;
+       return;
+    }
+    info->info_dirs = dirs;
+    dirs[n_dirs + 1] = (char *)NULL;
+    dirs[n_dirs] = malloc((unsigned)strlen(info_dir)+1);
+    strcpy(dirs[n_dirs], info_dir);
+    *code_ptr = 0;
+}
+
+void ss_delete_info_dir(sci_idx, info_dir, code_ptr)
+    int sci_idx;
+    char *info_dir;
+    int *code_ptr;
+{
+    register char **i_d;
+    register char **info_dirs;
+
+    info_dirs = ss_info(sci_idx)->info_dirs;
+    for (i_d = info_dirs; *i_d; i_d++) {
+       if (!strcmp(*i_d, info_dir)) {
+           while (*i_d) {
+               *i_d = *(i_d+1);
+               i_d++;
+           }
+           *code_ptr = 0;
+           return;
+       }
+    }
+    *code_ptr = SS_ET_NO_INFO_DIR;
+}
diff --git a/lib/ss/invocation.c b/lib/ss/invocation.c
new file mode 100644 (file)
index 0000000..678bbcd
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+#include "ss_internal.h"
+#include "copyright.h"
+#define        size    sizeof(ss_data *)
+
+#ifndef lint
+static char const rcsid[] =
+    "$Header$";
+#endif
+
+int ss_create_invocation(subsystem_name, version_string, info_ptr,
+                        request_table_ptr, code_ptr)
+       char *subsystem_name, *version_string;
+       char *info_ptr;
+       ss_request_table *request_table_ptr;
+       int *code_ptr;
+{
+       register int sci_idx;
+       register ss_data *new_table;
+       register ss_data **table;
+
+       *code_ptr = 0;
+       table = _ss_table;
+       new_table = (ss_data *) malloc(sizeof(ss_data));
+
+       if (table == (ss_data **) NULL) {
+               table = (ss_data **) malloc(2 * size);
+               table[0] = table[1] = (ss_data *)NULL;
+       }
+       initialize_ss_error_table ();
+
+       for (sci_idx = 1; table[sci_idx] != (ss_data *)NULL; sci_idx++)
+               ;
+       table = (ss_data **) realloc((char *)table,
+                                    ((unsigned)sci_idx+2)*size);
+       table[sci_idx+1] = (ss_data *) NULL;
+       table[sci_idx] = new_table;
+
+       new_table->subsystem_name = subsystem_name;
+       new_table->subsystem_version = version_string;
+       new_table->argv = (char **)NULL;
+       new_table->current_request = (char *)NULL;
+       new_table->info_dirs = (char **)malloc(sizeof(char *));
+       *new_table->info_dirs = (char *)NULL;
+       new_table->info_ptr = info_ptr;
+       new_table->prompt = malloc((unsigned)strlen(subsystem_name)+4);
+       strcpy(new_table->prompt, subsystem_name);
+       strcat(new_table->prompt, ":  ");
+#ifdef silly
+       new_table->abbrev_info = ss_abbrev_initialize("/etc/passwd", code_ptr);
+#else
+       new_table->abbrev_info = NULL;
+#endif
+       new_table->flags.escape_disabled = 0;
+       new_table->flags.abbrevs_disabled = 0;
+       new_table->rqt_tables =
+               (ss_request_table **) calloc(2, sizeof(ss_request_table *));
+       *(new_table->rqt_tables) = request_table_ptr;
+       *(new_table->rqt_tables+1) = (ss_request_table *) NULL;
+       _ss_table = table;
+       return(sci_idx);
+}
+
+void
+ss_delete_invocation(sci_idx)
+       int sci_idx;
+{
+       register ss_data *t;
+       int ignored_code;
+
+       t = ss_info(sci_idx);
+       free(t->prompt);
+       free((char *)t->rqt_tables);
+       while(t->info_dirs[0] != (char *)NULL)
+               ss_delete_info_dir(sci_idx, t->info_dirs[0], &ignored_code);
+       free((char *)t->info_dirs);
+       free((char *)t);
+}
diff --git a/lib/ss/list_rqs.c b/lib/ss/list_rqs.c
new file mode 100644 (file)
index 0000000..14877bb
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+#include "copyright.h"
+#include "ss_internal.h"
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+
+typedef void sigret_t;
+
+#ifdef lint     /* "lint returns a value which is sometimes ignored" */
+#define DONT_USE(x)     x=x;
+#else /* !lint */
+#define DONT_USE(x)     ;
+#endif /* lint */
+
+static char const twentyfive_spaces[26] =
+    "                         ";
+static char const NL[2] = "\n";
+
+ss_list_requests(argc, argv, sci_idx, info_ptr)
+    int argc;
+    char **argv;
+    int sci_idx;
+    pointer info_ptr;
+{
+    register ss_request_entry *entry;
+    register char const * const *name;
+    register int spacing;
+    register ss_request_table **table;
+
+    char buffer[BUFSIZ];
+    FILE *output;
+    int fd;
+    int mask;
+    sigret_t (*func)();
+#ifndef WAIT_USES_INT
+    union wait waitb;
+#else
+    int waitb;
+#endif
+
+    DONT_USE(argc);
+    DONT_USE(argv);
+
+    mask = sigblock(sigmask(SIGINT));
+    func = signal(SIGINT, SIG_IGN);
+    fd = ss_pager_create();
+    output = fdopen(fd, "w");
+    sigsetmask(mask);
+
+    fprintf (output, "Available %s requests:\n\n",
+            ss_info (sci_idx) -> subsystem_name);
+
+    for (table = ss_info(sci_idx)->rqt_tables; *table; table++) {
+        entry = (*table)->requests;
+        for (; entry->command_names; entry++) {
+            spacing = -2;
+            buffer[0] = '\0';
+            if (entry->flags & SS_OPT_DONT_LIST)
+                continue;
+            for (name = entry->command_names; *name; name++) {
+                register int len = strlen(*name);
+                strncat(buffer, *name, len);
+                spacing += len + 2;
+                if (name[1]) {
+                    strcat(buffer, ", ");
+                }
+            }
+            if (spacing > 23) {
+                strcat(buffer, NL);
+                fputs(buffer, output);
+                spacing = 0;
+                buffer[0] = '\0';
+            }
+            strncat(buffer, twentyfive_spaces, 25-spacing);
+            strcat(buffer, entry->info_string);
+            strcat(buffer, NL);
+            fputs(buffer, output);
+        }
+    }
+    fclose(output);
+#ifndef NO_FORK
+    wait(&waitb);
+#endif
+    (void) signal(SIGINT, func);
+}
diff --git a/lib/ss/listen.c b/lib/ss/listen.c
new file mode 100644 (file)
index 0000000..13844a0
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Listener loop for subsystem library libss.a.
+ *
+ *     $Header$
+ *     $Locker$
+ * 
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include "copyright.h"
+#include "ss_internal.h"
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/param.h>
+#ifdef BSD
+#include <sgtty.h>
+#endif
+
+#ifndef        lint
+static char const rcs_id[] =
+    "$Header$";
+#endif
+
+typedef void sigret_t;
+
+static ss_data *current_info;
+static jmp_buf listen_jmpb;
+
+static sigret_t print_prompt()
+{
+#ifdef BSD
+    /* put input into a reasonable mode */
+    struct sgttyb ttyb;
+    if (ioctl(fileno(stdin), TIOCGETP, &ttyb) != -1) {
+       if (ttyb.sg_flags & (CBREAK|RAW)) {
+           ttyb.sg_flags &= ~(CBREAK|RAW);
+           (void) ioctl(0, TIOCSETP, &ttyb);
+       }
+    }
+#endif
+    (void) fputs(current_info->prompt, stdout);
+    (void) fflush(stdout);
+}
+
+static sigret_t listen_int_handler()
+{
+    putc('\n', stdout);
+    signal(SIGINT, listen_int_handler);
+    longjmp(listen_jmpb, 1);
+}
+
+int ss_listen (sci_idx)
+    int sci_idx;
+{
+    char *cp;
+    ss_data *info;
+    sigret_t (*sig_int)(), (*sig_cont)(), (*old_sig_cont)();
+    char input[BUFSIZ];
+    char buffer[BUFSIZ];
+    char *end = buffer;
+    int mask;
+    int code;
+    jmp_buf old_jmpb;
+    ss_data *old_info = current_info;
+    
+    current_info = info = ss_info(sci_idx);
+    sig_cont = (sigret_t (*)()) 0;
+    info->abort = 0;
+    mask = sigblock(sigmask(SIGINT));
+    memcpy(old_jmpb, listen_jmpb, sizeof(jmp_buf));
+    sig_int = signal(SIGINT, listen_int_handler);
+    setjmp(listen_jmpb);
+    (void) sigsetmask(mask);
+    while(!info->abort) {
+       print_prompt();
+       *end = '\0';
+       old_sig_cont = sig_cont;
+       sig_cont = signal(SIGCONT, print_prompt);
+       if (sig_cont == print_prompt)
+           sig_cont = old_sig_cont;
+       if (fgets(input, BUFSIZ, stdin) != input) {
+           code = SS_ET_EOF;
+           goto egress;
+       }
+       cp = strchr(input, '\n');
+       if (cp) {
+           *cp = '\0';
+           if (cp == input)
+               continue;
+       }
+       (void) signal(SIGCONT, sig_cont);
+       for (end = input; *end; end++)
+           ;
+
+       code = ss_execute_line (sci_idx, input);
+       if (code == SS_ET_COMMAND_NOT_FOUND) {
+           register char *c = input;
+           while (*c == ' ' || *c == '\t')
+               c++;
+           cp = strchr (c, ' ');
+           if (cp)
+               *cp = '\0';
+           cp = strchr (c, '\t');
+           if (cp)
+               *cp = '\0';
+           ss_error (sci_idx, 0,
+                   "Unknown request \"%s\".  Type \"?\" for a request list.",
+                      c);
+       }
+    }
+    code = 0;
+egress:
+    (void) signal(SIGINT, sig_int);
+    memcpy(listen_jmpb, old_jmpb, sizeof(jmp_buf));
+    current_info = old_info;
+    return code;
+}
+
+void ss_abort_subsystem(sci_idx, code)
+    int sci_idx;
+    int code;
+{
+    ss_info(sci_idx)->abort = 1;
+    ss_info(sci_idx)->exit_status = code;
+    
+}
+
+int ss_quit(argc, argv, sci_idx, infop)
+    int argc;
+    char **argv;
+    int sci_idx;
+    pointer infop;
+{
+    ss_abort_subsystem(sci_idx, 0);
+}
diff --git a/lib/ss/mit-sipb-copyright.h b/lib/ss/mit-sipb-copyright.h
new file mode 100644 (file)
index 0000000..ffcfc38
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+
+Copyright 1987 by the Student Information Processing Board
+       of the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is
+hereby granted, provided that the above copyright notice
+appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation,
+and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+M.I.T. and the M.I.T. S.I.P.B. make no representations about
+the suitability of this software for any purpose.  It is
+provided "as is" without express or implied warranty.
+
+*/
+
diff --git a/lib/ss/mk_cmds.sh b/lib/ss/mk_cmds.sh
new file mode 100644 (file)
index 0000000..eda3888
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+#
+
+DIR=@DIR@
+AWK=@AWK@
+SED=@SED@
+
+FILE=$1
+ROOT=`echo $1 | sed -e s/.ct$//`
+BASE=`basename $ROOT`
+TMP=ct$$.c
+
+${SED} -f ${DIR}/ct_c.sed  ${FILE} \
+       | ${AWK} -f ${DIR}/ct_c.awk rootname=${ROOT} outfile=${TMP} -
+
+if grep "^#__ERROR_IN_FILE" ${TMP} > /dev/null; then
+       rm ${TMP}
+       exit 1
+else
+       mv ${TMP} ${BASE}.c
+       exit 0
+fi
diff --git a/lib/ss/pager.c b/lib/ss/pager.c
new file mode 100644 (file)
index 0000000..b951fa6
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Pager: Routines to create a "more" running out of a particular file
+ * descriptor.
+ *
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include "ss_internal.h"
+#include "copyright.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <signal.h>
+
+static char MORE[] = "more";
+extern char *_ss_pager_name;
+extern char *getenv();
+extern int errno;
+
+/*
+ * this needs a *lot* of work....
+ *
+ * run in same process
+ * handle SIGINT sensibly
+ * allow finer control -- put-page-break-here
+ */
+void ss_page_stdin();
+
+#ifndef NO_FORK
+int ss_pager_create() 
+{
+       int filedes[2];
+     
+       if (pipe(filedes) != 0)
+               return(-1);
+
+       switch(fork()) {
+       case -1:
+               return(-1);
+       case 0:
+               /*
+                * Child; dup read half to 0, close all but 0, 1, and 2
+                */
+               if (dup2(filedes[0], 0) == -1)
+                       exit(1);
+               ss_page_stdin();
+       default:
+               /*
+                * Parent:  close "read" side of pipe, return
+                * "write" side.
+                */
+               (void) close(filedes[0]);
+               return(filedes[1]);
+       }
+}
+#else /* don't fork */
+int ss_pager_create()
+{
+    int fd;
+    fd = open("/dev/tty", O_WRONLY, 0);
+    return fd;
+}
+#endif
+
+void ss_page_stdin()
+{
+       int i;
+       for (i = 3; i < 32; i++)
+               (void) close(i);
+       (void) signal(SIGINT, SIG_DFL);
+       {
+               int mask = sigblock(0);
+               mask &= ~sigmask(SIGINT);
+               sigsetmask(mask);
+       }
+       if (_ss_pager_name == (char *)NULL) {
+               if ((_ss_pager_name = getenv("PAGER")) == (char *)NULL)
+                       _ss_pager_name = MORE;
+       }
+       (void) execlp(_ss_pager_name, _ss_pager_name, (char *) NULL);
+       {
+               /* minimal recovery if pager program isn't found */
+               char buf[80];
+               register int n;
+               while ((n = read(0, buf, 80)) > 0)
+                       write(1, buf, n);
+       }
+       exit(errno);
+}
diff --git a/lib/ss/parse.c b/lib/ss/parse.c
new file mode 100644 (file)
index 0000000..e1dec31
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright info, see copyright.h.
+ */
+
+#include "ss_internal.h"
+#include "copyright.h"
+
+#ifndef lint
+static char const rcsid[] =
+    "$Header$";
+#endif
+
+enum parse_mode { WHITESPACE, TOKEN, QUOTED_STRING };
+
+/*
+ * parse(line_ptr, argc_ptr)
+ *
+ * Function:
+ *      Parses line, dividing at whitespace, into tokens, returns
+ *      the "argc" and "argv" values.
+ * Arguments:
+ *      line_ptr (char *)
+ *              Pointer to text string to be parsed.
+ *      argc_ptr (int *)
+ *              Where to put the "argc" (number of tokens) value.
+ * Returns:
+ *      argv (char **)
+ *              Series of pointers to parsed tokens.
+ */
+
+#define NEW_ARGV(old,n) (char **)realloc((char *)old,\
+                                        (unsigned)(n+2)*sizeof(char*))
+
+char **ss_parse (sci_idx, line_ptr, argc_ptr)
+    int sci_idx;
+    register char *line_ptr;
+    int *argc_ptr;
+{
+    register char **argv, *cp;
+    register int argc;
+    register enum parse_mode parse_mode;
+
+    argv = (char **) malloc (sizeof(char *));
+    if (argv == (char **)NULL) {
+       ss_error(sci_idx, errno, "Can't allocate storage");
+       *argc_ptr = 0;
+       return(argv);
+    }
+    *argv = (char *)NULL;
+
+    argc = 0;
+
+    parse_mode = WHITESPACE;   /* flushing whitespace */
+    cp = line_ptr;             /* cp is for output */
+    while (1) {
+#ifdef DEBUG
+       {
+           printf ("character `%c', mode %d\n", *line_ptr, parse_mode);
+       }
+#endif
+       while (parse_mode == WHITESPACE) {
+           if (*line_ptr == '\0')
+               goto end_of_line;
+           if (*line_ptr == ' ' || *line_ptr == '\t') {
+               line_ptr++;
+               continue;
+           }
+           if (*line_ptr == '"') {
+               /* go to quoted-string mode */
+               parse_mode = QUOTED_STRING;
+               cp = line_ptr++;
+               argv = NEW_ARGV (argv, argc);
+               argv[argc++] = cp;
+               argv[argc] = NULL;
+           }
+           else {
+               /* random-token mode */
+               parse_mode = TOKEN;
+               cp = line_ptr;
+               argv = NEW_ARGV (argv, argc);
+               argv[argc++] = line_ptr;
+               argv[argc] = NULL;
+           }
+       }
+       while (parse_mode == TOKEN) {
+           if (*line_ptr == '\0') {
+               *cp++ = '\0';
+               goto end_of_line;
+           }
+           else if (*line_ptr == ' ' || *line_ptr == '\t') {
+               *cp++ = '\0';
+               line_ptr++;
+               parse_mode = WHITESPACE;
+           }
+           else if (*line_ptr == '"') {
+               line_ptr++;
+               parse_mode = QUOTED_STRING;
+           }
+           else {
+               *cp++ = *line_ptr++;
+           }
+       }
+       while (parse_mode == QUOTED_STRING) {
+           if (*line_ptr == '\0') {
+               ss_error (sci_idx, 0,
+                         "Unbalanced quotes in command line");
+               free (argv);
+               *argc_ptr = 0;
+               return NULL;
+           }
+           else if (*line_ptr == '"') {
+               if (*++line_ptr == '"') {
+                   *cp++ = '"';
+                   line_ptr++;
+               }
+               else {
+                   parse_mode = TOKEN;
+               }
+           }
+           else {
+               *cp++ = *line_ptr++;
+           }
+       }
+    }
+end_of_line:
+    *argc_ptr = argc;
+#ifdef DEBUG
+    {
+       int i;
+       printf ("argc = %d\n", argc);
+       for (i = 0; i <= argc; i++)
+           printf ("\targv[%2d] = `%s'\n", i,
+                   argv[i] ? argv[i] : "<NULL>");
+    }
+#endif
+    return(argv);
+}
diff --git a/lib/ss/prompt.c b/lib/ss/prompt.c
new file mode 100644 (file)
index 0000000..bc95d82
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * prompt.c: Routines for retrieving and setting a prompt.
+ *
+ * $Header$
+ * $Locker$
+ *
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include "copyright.h"
+#include <stdio.h>
+#include "ss_internal.h"
+
+static const char rcsid[] =
+    "$Header$";
+
+ss_set_prompt(sci_idx, new_prompt)
+     int sci_idx;
+     char *new_prompt;
+{
+     ss_info(sci_idx)->prompt = new_prompt;
+}
+
+char *
+ss_get_prompt(sci_idx)
+     int sci_idx;
+{
+     return(ss_info(sci_idx)->prompt);
+}
diff --git a/lib/ss/request_tbl.c b/lib/ss/request_tbl.c
new file mode 100644 (file)
index 0000000..b15ba91
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include "copyright.h"
+#include "ss_internal.h"
+
+#define ssrt ss_request_table  /* for some readable code... */
+
+void ss_add_request_table(sci_idx, rqtbl_ptr, position, code_ptr)
+       int sci_idx;
+       ssrt *rqtbl_ptr;
+       int position;           /* 1 -> becomes second... */
+       int *code_ptr;
+{
+       register ss_data *info;
+       register int i, size;
+
+       info = ss_info(sci_idx);
+       for (size=0; info->rqt_tables[size] != (ssrt *)NULL; size++)
+               ;
+       /* size == C subscript of NULL == #elements */
+       size += 2;              /* new element, and NULL */
+       info->rqt_tables = (ssrt **)realloc((char *)info->rqt_tables,
+                                           (unsigned)size*sizeof(ssrt));
+       if (info->rqt_tables == (ssrt **)NULL) {
+               *code_ptr = errno;
+               return;
+       }
+       if (position > size - 2)
+               position = size - 2;
+
+       if (size > 1)
+               for (i = size - 2; i >= position; i--)
+                       info->rqt_tables[i+1] = info->rqt_tables[i];
+
+       info->rqt_tables[position] = rqtbl_ptr;
+       info->rqt_tables[size-1] = (ssrt *)NULL;
+       *code_ptr = 0;
+}
+
+void ss_delete_request_table(sci_idx, rqtbl_ptr, code_ptr)
+     int sci_idx;
+     ssrt *rqtbl_ptr;
+     int *code_ptr;
+{
+     register ss_data *info;
+     register ssrt **rt1, **rt2;
+
+     *code_ptr = SS_ET_TABLE_NOT_FOUND;
+     info = ss_info(sci_idx);
+     rt1 = info->rqt_tables;
+     for (rt2 = rt1; *rt1; rt1++) {
+         if (*rt1 != rqtbl_ptr) {
+              *rt2++ = *rt1;
+              *code_ptr = 0;
+         }
+     }
+     *rt2 = (ssrt *)NULL;
+     return;
+}
diff --git a/lib/ss/requests.c b/lib/ss/requests.c
new file mode 100644 (file)
index 0000000..bfe69f1
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Various minor routines...
+ *
+ * Copyright 1987, 1988, 1989 by MIT
+ *
+ * For copyright information, see mit-sipb-copyright.h.
+ */
+
+#include "mit-sipb-copyright.h"
+#include <stdio.h>
+#include "ss_internal.h"
+
+#define        DECLARE(name)   name(argc,argv,sci_idx)int argc,sci_idx;char **argv;
+
+/*
+ * ss_self_identify -- assigned by default to the "." request
+ */
+DECLARE(ss_self_identify)
+{
+     register ss_data *info = ss_info(sci_idx);
+     printf("%s version %s\n", info->subsystem_name,
+           info->subsystem_version);
+}
+
+/*
+ * ss_subsystem_name -- print name of subsystem
+ */
+DECLARE(ss_subsystem_name)
+{
+     printf("%s\n", ss_info(sci_idx)->subsystem_name);
+}
+
+/*
+ * ss_subsystem_version -- print version of subsystem
+ */
+DECLARE(ss_subsystem_version)
+{
+     printf("%s\n", ss_info(sci_idx)->subsystem_version);
+}
+
+/*
+ * ss_unimplemented -- routine not implemented (should be
+ * set up as (dont_list,dont_summarize))
+ */
+DECLARE(ss_unimplemented)
+{
+     ss_perror(sci_idx, SS_ET_UNIMPLEMENTED, "");
+}
diff --git a/lib/ss/ss.h b/lib/ss/ss.h
new file mode 100644 (file)
index 0000000..4fa3ebe
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see mit-sipb-copyright.h.
+ */
+
+#ifndef _ss_h
+#define _ss_h __FILE__
+
+#include <ss/mit-sipb-copyright.h>
+#include <ss/ss_err.h>
+
+extern int errno;
+
+#ifdef __STDC__
+#define __SS_CONST const
+#define __SS_PROTO (int, const char * const *, int, void *)
+#else
+#define __SS_CONST
+#define __SS_PROTO ()
+#endif
+
+typedef __SS_CONST struct _ss_request_entry {
+    __SS_CONST char * __SS_CONST *command_names; /* whatever */
+    void (* __SS_CONST function) __SS_PROTO; /* foo */
+    __SS_CONST char * __SS_CONST info_string;  /* NULL */
+    int flags;                 /* 0 */
+} ss_request_entry;
+
+typedef __SS_CONST struct _ss_request_table {
+    int version;
+    ss_request_entry *requests;
+} ss_request_table;
+
+#define SS_RQT_TBL_V2  2
+
+typedef struct _ss_rp_options {        /* DEFAULT VALUES */
+    int version;               /* SS_RP_V1 */
+    void (*unknown) __SS_PROTO;        /* call for unknown command */
+    int allow_suspend;
+    int catch_int;
+} ss_rp_options;
+
+#define SS_RP_V1 1
+
+#define SS_OPT_DONT_LIST       0x0001
+#define SS_OPT_DONT_SUMMARIZE  0x0002
+
+void ss_help __SS_PROTO;
+char *ss_current_request();
+char *ss_name();
+#ifdef __STDC__
+void ss_error (int, long, char const *, ...);
+void ss_perror (int, long, char const *);
+int ss_create_invocation(char *, char *, char *, ss_request_table *, int *);
+void ss_delete_invocation(int);
+int ss_listen(int);
+void ss_add_request_table(int, ss_request_table *, int, int *);
+void ss_delete_request_table(int, ss_request_table *, int *);
+#else
+void ss_error ();
+void ss_perror ();
+int ss_create_invocation();
+void ss_delete_invocation();
+int ss_listen();
+void ss_add_request_table();
+void ss_delete_request_table();
+#endif
+void ss_abort_subsystem();
+extern ss_request_table ss_std_requests;
+#endif /* _ss_h */
diff --git a/lib/ss/ss_err.c b/lib/ss/ss_err.c
new file mode 100644 (file)
index 0000000..7b97a00
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * ss_err.c:
+ * This file is automatically generated; please do not edit it.
+ */
+#ifdef __STDC__
+#define NOARGS void
+#else
+#define NOARGS
+#define const
+#endif
+
+static const char * const text[] = {
+               "Subsystem aborted",
+               "Version mismatch",
+               "No current invocation",
+               "No info directory",
+               "Command not found",
+               "Command line aborted",
+               "End-of-file reached",
+               "Permission denied",
+               "Request table not found",
+               "No info available",
+               "Shell escapes are disabled",
+               "Sorry, this request is not yet implemented",
+    0
+};
+
+struct error_table {
+    char const * const * msgs;
+    long base;
+    int n_msgs;
+};
+struct et_list {
+    struct et_list *next;
+    const struct error_table * table;
+};
+extern struct et_list *_et_list;
+
+static const struct error_table et = { text, 748800L, 12 };
+
+static struct et_list link = { 0, 0 };
+
+void initialize_ss_error_table (NOARGS);
+
+void initialize_ss_error_table (NOARGS) {
+    if (!link.table) {
+        link.next = _et_list;
+        link.table = &et;
+        _et_list = &link;
+    }
+}
diff --git a/lib/ss/ss_err.et b/lib/ss/ss_err.et
new file mode 100644 (file)
index 0000000..80e9dfa
--- /dev/null
@@ -0,0 +1,39 @@
+       error_table ss
+
+ec     SS_ET_SUBSYSTEM_ABORTED,
+       "Subsystem aborted"
+
+ec     SS_ET_VERSION_MISMATCH,
+       "Version mismatch"
+
+ec     SS_ET_NULL_INV,
+       "No current invocation"
+
+ec     SS_ET_NO_INFO_DIR,
+       "No info directory"
+
+ec     SS_ET_COMMAND_NOT_FOUND,
+       "Command not found"
+
+ec     SS_ET_LINE_ABORTED,
+       "Command line aborted"
+
+ec     SS_ET_EOF,
+       "End-of-file reached"
+
+ec     SS_ET_PERMISSION_DENIED,
+       "Permission denied"
+
+ec     SS_ET_TABLE_NOT_FOUND,
+       "Request table not found"
+
+ec     SS_ET_NO_HELP_FILE,
+       "No info available"
+
+ec     SS_ET_ESCAPE_DISABLED,
+       "Shell escapes are disabled"
+
+ec     SS_ET_UNIMPLEMENTED,
+       "Sorry, this request is not yet implemented"
+
+       end
diff --git a/lib/ss/ss_err.h b/lib/ss/ss_err.h
new file mode 100644 (file)
index 0000000..02ab507
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * ss_err.h:
+ * This file is automatically generated; please do not edit it.
+ */
+#ifdef __STDC__
+#define NOARGS void
+#else
+#define NOARGS
+#define const
+#endif
+
+#define SS_ET_SUBSYSTEM_ABORTED                  (748800L)
+#define SS_ET_VERSION_MISMATCH                   (748801L)
+#define SS_ET_NULL_INV                           (748802L)
+#define SS_ET_NO_INFO_DIR                        (748803L)
+#define SS_ET_COMMAND_NOT_FOUND                  (748804L)
+#define SS_ET_LINE_ABORTED                       (748805L)
+#define SS_ET_EOF                                (748806L)
+#define SS_ET_PERMISSION_DENIED                  (748807L)
+#define SS_ET_TABLE_NOT_FOUND                    (748808L)
+#define SS_ET_NO_HELP_FILE                       (748809L)
+#define SS_ET_ESCAPE_DISABLED                    (748810L)
+#define SS_ET_UNIMPLEMENTED                      (748811L)
+extern void initialize_ss_error_table (NOARGS);
+#define ERROR_TABLE_BASE_ss (748800L)
+
+/* for compatibility with older versions... */
+#define init_ss_err_tbl initialize_ss_error_table
+#define ss_err_base ERROR_TABLE_BASE_ss
diff --git a/lib/ss/ss_internal.h b/lib/ss/ss_internal.h
new file mode 100644 (file)
index 0000000..4b9ea23
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#ifndef _ss_ss_internal_h
+#define _ss_ss_internal_h __FILE__
+#include <stdio.h>
+#include <string.h>
+
+#ifdef __STDC__
+
+#define PROTOTYPE(p) p
+typedef void * pointer;
+
+#else
+
+#define const
+#define volatile
+#define PROTOTYPE(p) ()
+typedef char * pointer;
+
+#endif /* not __STDC__ */
+
+#include "ss.h"
+
+#if defined(__GNUC__)
+#define LOCAL_ALLOC(x) __builtin_alloca(x)
+#define LOCAL_FREE(x)
+#else
+#if defined(vax)
+#define LOCAL_ALLOC(x) alloca(x)
+#define LOCAL_FREE(x)
+extern pointer alloca PROTOTYPE((unsigned));
+#else
+#if defined(__HIGHC__) /* Barf! */
+pragma on(alloca);
+#define LOCAL_ALLOC(x) alloca(x)
+#define LOCAL_FREE(x)
+extern pointer alloca PROTOTYPE((unsigned));
+#else
+/* no alloca? */
+#define LOCAL_ALLOC(x) malloc(x)
+#define LOCAL_FREE(x) free(x)
+#endif
+#endif
+#endif                         /* LOCAL_ALLOC stuff */
+
+typedef char BOOL;
+
+typedef struct _ss_abbrev_entry {
+    char *name;                        /* abbrev name */
+    char **abbrev;             /* new tokens to insert */
+    unsigned int beginning_of_line : 1;
+} ss_abbrev_entry;
+
+typedef struct _ss_abbrev_list {
+    int n_abbrevs;
+    ss_abbrev_entry *first_abbrev;
+} ss_abbrev_list;
+
+typedef struct {
+/*    char *path; */
+    ss_abbrev_list abbrevs[127];
+} ss_abbrev_info;
+
+typedef struct _ss_data {      /* init values */
+    /* this subsystem */
+    char *subsystem_name;
+    char *subsystem_version;
+    /* current request info */
+    int argc;
+    char **argv;               /* arg list */
+    char const *current_request; /* primary name */
+    /* info directory for 'help' */
+    char **info_dirs;
+    /* to be extracted by subroutines */
+    pointer info_ptr;          /* (void *) NULL */
+    /* for ss_listen processing */
+    char *prompt;
+    ss_request_table **rqt_tables;
+    ss_abbrev_info *abbrev_info;
+    struct {
+       unsigned int  escape_disabled : 1,
+                     abbrevs_disabled : 1;
+    } flags;
+    /* to get out */
+    int abort;                 /* exit subsystem */
+    int exit_status;
+} ss_data;
+
+#define CURRENT_SS_VERSION 1
+
+#define        ss_info(sci_idx)        (_ss_table[sci_idx])
+#define        ss_current_request(sci_idx,code_ptr)    \
+     (*code_ptr=0,ss_info(sci_idx)->current_request)
+void ss_unknown_function();
+void ss_delete_info_dir();
+int ss_execute_line();
+char **ss_parse();
+ss_abbrev_info *ss_abbrev_initialize PROTOTYPE((char *, int *));
+void ss_page_stdin();
+
+extern ss_data **_ss_table;
+extern char *ss_et_msgs[];
+
+extern pointer malloc PROTOTYPE((unsigned));
+extern pointer realloc PROTOTYPE((pointer, unsigned));
+extern pointer calloc PROTOTYPE((unsigned, unsigned));
+
+#ifdef USE_SIGPROCMASK
+/* fake sigmask, sigblock, sigsetmask */
+#include <signal.h>
+#define sigmask(x) (1L<<(x)-1)
+#define sigsetmask(x) sigprocmask(SIG_SETMASK,&x,NULL)
+static int _fake_sigstore;
+#define sigblock(x) (_fake_sigstore=x,sigprocmask(SIG_BLOCK,&_fake_sigstore,0))
+#endif
+#endif /* _ss_internal_h */
diff --git a/lib/ss/std_rqs.c b/lib/ss/std_rqs.c
new file mode 100644 (file)
index 0000000..d0f0ccb
--- /dev/null
@@ -0,0 +1,108 @@
+/* std_rqs.c - automatically generated from std_rqs.ct */
+#include <ss/ss.h>
+
+#ifndef __STDC__
+#define const
+#endif
+
+static char const * const ssu00001[] = {
+".",
+    (char const *)0
+};
+extern void ss_self_identify __SS_PROTO;
+static char const * const ssu00002[] = {
+"help",
+    (char const *)0
+};
+extern void ss_help __SS_PROTO;
+static char const * const ssu00003[] = {
+"list_help",
+    "lh",
+    (char const *)0
+};
+extern void ss_unimplemented __SS_PROTO;
+static char const * const ssu00004[] = {
+"list_requests",
+    "lr",
+    "?",
+    (char const *)0
+};
+extern void ss_list_requests __SS_PROTO;
+static char const * const ssu00005[] = {
+"quit",
+    "q",
+    (char const *)0
+};
+extern void ss_quit __SS_PROTO;
+static char const * const ssu00006[] = {
+"abbrev",
+    "ab",
+    (char const *)0
+};
+extern void ss_unimplemented __SS_PROTO;
+static char const * const ssu00007[] = {
+"execute",
+    "e",
+    (char const *)0
+};
+extern void ss_unimplemented __SS_PROTO;
+static char const * const ssu00008[] = {
+"?",
+    (char const *)0
+};
+extern void ss_unimplemented __SS_PROTO;
+static char const * const ssu00009[] = {
+"subsystem_name",
+    (char const *)0
+};
+extern void ss_subsystem_name __SS_PROTO;
+static char const * const ssu00010[] = {
+"subsystem_version",
+    (char const *)0
+};
+extern void ss_subsystem_version __SS_PROTO;
+static ss_request_entry ssu00011[] = {
+    { ssu00001,
+      ss_self_identify,
+      "Identify the subsystem.",
+      3 },
+    { ssu00002,
+      ss_help,
+      "Display info on command or topic.",
+      0 },
+    { ssu00003,
+      ss_unimplemented,
+      "List topics for which help is available.",
+      3 },
+    { ssu00004,
+      ss_list_requests,
+      "List available commands.",
+      0 },
+    { ssu00005,
+      ss_quit,
+      "Leave the subsystem.",
+      0 },
+    { ssu00006,
+      ss_unimplemented,
+      "Enable/disable abbreviation processing of request lines.",
+      3 },
+    { ssu00007,
+      ss_unimplemented,
+      "Execute a UNIX command line.",
+      3 },
+    { ssu00008,
+      ss_unimplemented,
+      "Produce a list of the most commonly used requests.",
+      3 },
+    { ssu00009,
+      ss_subsystem_name,
+      "Return the name of this subsystem.",
+      1 },
+    { ssu00010,
+      ss_subsystem_version,
+      "Return the version of this subsystem.",
+      1 },
+    { 0, 0, 0, 0 }
+};
+
+ss_request_table ss_std_requests = { 2, ssu00011 };
diff --git a/lib/ss/std_rqs.ct b/lib/ss/std_rqs.ct
new file mode 100644 (file)
index 0000000..500288a
--- /dev/null
@@ -0,0 +1,46 @@
+       command_table   ss_std_requests;
+
+       request ss_self_identify, "Identify the subsystem.",
+               ".",
+               (dont_list, dont_summarize);
+
+       request ss_help, "Display info on command or topic.",
+               help;
+
+       unimplemented
+               ss_list_help,
+               "List topics for which help is available.",
+               list_help, lh;
+
+       request ss_list_requests, "List available commands.",
+               list_requests, lr, "?";
+
+       request ss_quit, "Leave the subsystem.",
+               quit, q;
+
+       unimplemented
+               ss_abbrev,
+               "Enable/disable abbreviation processing of request lines.",
+               abbrev, ab;
+
+       unimplemented
+               ss_execute,
+               "Execute a UNIX command line.",
+               execute, e;
+
+       unimplemented
+               ss_summarize_requests,
+               "Produce a list of the most commonly used requests.",
+               "?";
+               
+       request ss_subsystem_name,
+               "Return the name of this subsystem.",
+               subsystem_name,
+               (dont_list);
+
+       request ss_subsystem_version,
+               "Return the version of this subsystem.",
+               subsystem_version,
+               (dont_list);
+
+       end;
diff --git a/lib/ss/test_ss.c b/lib/ss/test_ss.c
new file mode 100644 (file)
index 0000000..502256d
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ *------------------------------------------------------------------
+ *
+ * $Source$
+ * $Revision$
+ * $Date$
+ * $State$
+ * $Author$
+ * $Locker$
+ *
+ * $Log$
+ * Revision 1.1  1997/04/26 13:21:42  tytso
+ * Checkin of e2fsprogs 0.5
+ *
+ * Revision 1.1  1993/06/03  12:31:25  tytso
+ * Initial revision
+ *
+ * Revision 1.1  1991/12/21  16:41:47  eichin
+ * Initial revision
+ *
+ * Revision 1.1  1991/12/21  11:13:39  eichin
+ * Initial revision
+ *
+ * Revision 1.2  89/01/25  07:52:27  raeburn
+ * *** empty log message ***
+ * 
+ * Revision 1.1  88/01/23  15:50:26  raeburn
+ * Initial revision
+ *
+ *
+ *------------------------------------------------------------------
+ */
+
+#ifndef lint
+static char const rcsid_test_c[] =
+    "$Header$";
+#endif /* lint */
+
+#include <stdio.h>
+#include "ss.h"
+
+extern ss_request_table test_cmds;
+
+#define TRUE 1
+#define FALSE 0
+
+static char def_subsystem_name[5] = "test";
+static char version [4] = "1.0";
+extern void ss_listen();
+
+int main(argc, argv)
+    int argc;
+    char **argv;
+{
+    int code;
+    char *argv0 = argv[0];
+    char *initial_request = (char *)NULL;
+    int quit = FALSE;  /* quit after processing request */
+    int sci_idx;
+    char *subsystem_name;
+
+    subsystem_name = def_subsystem_name;
+
+    for (; *argv; ++argv, --argc) {
+       printf("checking arg: %s\n", *argv);
+       if (!strcmp(*argv, "-prompt")) {
+           if (argc == 1) {
+               fprintf(stderr,
+                       "No argument supplied with -prompt\n");
+               exit(1);
+           }
+           argc--; argv++;
+           subsystem_name = *argv;
+       }
+       else if (!strcmp(*argv, "-request") || !strcmp(*argv, "-rq")) {
+           if (argc == 1) {
+               fprintf(stderr,
+                       "No string supplied with -request.\n");
+               exit(1);
+           }
+           argc--; argv++;
+           initial_request = *argv;
+       }
+       else if (!strcmp(*argv, "-quit"))
+           quit = TRUE;
+       else if (!strcmp(*argv, "-no_quit"))
+           quit = FALSE;
+       else if (**argv == '-') {
+           fprintf(stderr, "Unknown control argument %s\n",
+                   *argv);
+           fprintf(stderr,
+       "Usage: %s [gateway] [ -prompt name ] [ -request name ] [ -quit ]\n",
+                   argv0);
+           exit(1);
+       }
+    }
+
+    sci_idx = ss_create_invocation(subsystem_name, version,
+                                  (char *)NULL, &test_cmds, &code);
+    if (code) {
+       ss_perror(sci_idx, code, "creating invocation");
+       exit(1);
+    }
+
+    (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &code);
+    if (code) {
+       ss_perror (sci_idx, code, "adding standard requests");
+       exit (1);
+    }
+
+    if (!quit)
+       printf("test version %s.  Type '?' for a list of commands.\n\n",
+              version);
+
+    if (initial_request != (char *)NULL) {
+       code = ss_execute_line(sci_idx, initial_request);
+       if (code != 0)
+           ss_perror(sci_idx, code, initial_request);
+    }
+    if (!quit || code)
+       (void) ss_listen (sci_idx, &code);
+    exit(0);
+}
+
+
+void test_cmd (argc, argv)
+    int argc;
+    char **argv;
+{
+    while (++argv, --argc)
+       fputs(*argv, stdout);
+    putchar ('\n');
+}
diff --git a/misc/.depend b/misc/.depend
new file mode 100644 (file)
index 0000000..40b033a
--- /dev/null
@@ -0,0 +1,98 @@
+badblocks.o : badblocks.c /usr/include/errno.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/linux/errno.h /usr/include/fcntl.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/linux/fcntl.h /usr/include/getopt.h /usr/include/signal.h /usr/include/linux/signal.h \
+  /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h /usr/include/stdlib.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/string.h /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h \
+  /usr/include/sys/ioctl.h /usr/include/linux/ioctl.h /usr/include/termios.h /usr/include/linux/termios.h \
+  /usr/include/linux/fd.h /usr/include/linux/fs.h /usr/include/linux/linkage.h \
+  /usr/include/linux/limits.h /usr/include/linux/wait.h /usr/include/linux/dirent.h \
+  /usr/include/linux/vfs.h /usr/include/linux/net.h /usr/include/linux/socket.h \
+  /usr/include/linux/sockios.h /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h \
+  /usr/include/linux/ext_fs_i.h /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h \
+  /usr/include/linux/msdos_fs_i.h /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h \
+  /usr/include/linux/nfs.h /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h \
+  /usr/include/linux/minix_fs_sb.h /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h \
+  /usr/include/linux/hpfs_fs_sb.h /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h \
+  /usr/include/linux/nfs_fs_sb.h /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h \
+  ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h 
+chattr.o : chattr.c /usr/include/dirent.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h /usr/include/fcntl.h /usr/include/linux/fcntl.h \
+  /usr/include/getopt.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \
+  /usr/include/stdlib.h /usr/include/errno.h /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/sys/param.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/limits.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/syslimits.h /usr/include/limits.h \
+  /usr/include/posix1_lim.h /usr/include/linux/param.h /usr/include/sys/stat.h \
+  /usr/include/linux/stat.h /usr/include/linux/ext2_fs.h ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../lib/e2p/e2p.h ../version.h 
+dumpe2fs.o : dumpe2fs.c /usr/include/getopt.h /usr/include/fcntl.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/sys/types.h /usr/include/linux/types.h \
+  /usr/include/linux/fcntl.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \
+  /usr/include/stdlib.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/errno.h \
+  /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/string.h /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h \
+  /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../lib/ext2fs/io.h ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h ../lib/e2p/e2p.h \
+  /usr/include/dirent.h /usr/include/linux/limits.h /usr/include/linux/dirent.h \
+  ../version.h 
+fsck.o : fsck.c /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/sys/wait.h \
+  /usr/include/features.h /usr/include/sys/cdefs.h /usr/include/gnu/types.h /usr/include/waitflags.h \
+  /usr/include/waitstatus.h /usr/include/errno.h /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/limits.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/syslimits.h /usr/include/limits.h \
+  /usr/include/posix1_lim.h /usr/include/linux/limits.h /usr/include/stdio.h /usr/include/libio.h \
+  /usr/include/_G_config.h /usr/include/stdlib.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h /usr/include/string.h /usr/include/mntent.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/getopt.h ../version.h \
+  fsck.h 
+lsattr.o : lsattr.c /usr/include/dirent.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/gnu/types.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/limits.h \
+  /usr/include/linux/dirent.h /usr/include/errno.h /usr/include/linux/errno.h \
+  /usr/include/fcntl.h /usr/include/linux/fcntl.h /usr/include/getopt.h /usr/include/stdio.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/sys/param.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/limits.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/syslimits.h /usr/include/limits.h \
+  /usr/include/posix1_lim.h /usr/include/linux/param.h /usr/include/sys/stat.h \
+  /usr/include/linux/stat.h /usr/include/linux/ext2_fs.h ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h \
+  ../lib/e2p/e2p.h ../version.h 
+mke2fs.o : mke2fs.c /usr/include/string.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/fcntl.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/linux/fcntl.h /usr/include/ctype.h /usr/include/termios.h \
+  /usr/include/linux/termios.h /usr/include/time.h /usr/include/getopt.h /usr/include/unistd.h \
+  /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/stdlib.h /usr/include/errno.h \
+  /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/mntent.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \
+  /usr/include/malloc.h /usr/include/sys/ioctl.h /usr/include/linux/ioctl.h /usr/include/linux/ext2_fs.h \
+  /usr/include/linux/fs.h /usr/include/linux/linkage.h /usr/include/linux/limits.h \
+  /usr/include/linux/wait.h /usr/include/linux/dirent.h /usr/include/linux/vfs.h \
+  /usr/include/linux/net.h /usr/include/linux/socket.h /usr/include/linux/sockios.h \
+  /usr/include/linux/pipe_fs_i.h /usr/include/linux/minix_fs_i.h /usr/include/linux/ext_fs_i.h \
+  /usr/include/linux/ext2_fs_i.h /usr/include/linux/hpfs_fs_i.h /usr/include/linux/msdos_fs_i.h \
+  /usr/include/linux/iso_fs_i.h /usr/include/linux/nfs_fs_i.h /usr/include/linux/nfs.h \
+  /usr/include/linux/xia_fs_i.h /usr/include/linux/sysv_fs_i.h /usr/include/linux/minix_fs_sb.h \
+  /usr/include/linux/ext_fs_sb.h /usr/include/linux/ext2_fs_sb.h /usr/include/linux/hpfs_fs_sb.h \
+  /usr/include/linux/msdos_fs_sb.h /usr/include/linux/iso_fs_sb.h /usr/include/linux/nfs_fs_sb.h \
+  /usr/include/linux/xia_fs_sb.h /usr/include/linux/sysv_fs_sb.h ../lib/et/com_err.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../lib/ext2fs/ext2fs.h ../lib/ext2fs/io.h \
+  ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h ../version.h 
+mklost+found.o : mklost+found.c /usr/include/errno.h /usr/include/features.h \
+  /usr/include/sys/cdefs.h /usr/include/linux/errno.h /usr/include/fcntl.h /usr/include/sys/types.h \
+  /usr/include/linux/types.h /usr/include/linux/fcntl.h /usr/include/stdio.h /usr/include/libio.h \
+  /usr/include/_G_config.h /usr/include/string.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h \
+  /usr/include/unistd.h /usr/include/posix_opt.h /usr/include/gnu/types.h /usr/include/sys/param.h \
+  /usr/lib/gcc-lib/i486-linux/2.5.8/include/limits.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/syslimits.h \
+  /usr/include/limits.h /usr/include/posix1_lim.h /usr/include/linux/limits.h \
+  /usr/include/linux/param.h /usr/include/sys/stat.h /usr/include/linux/stat.h \
+  /usr/include/linux/ext2_fs.h ../version.h 
+tune2fs.o : tune2fs.c /usr/include/fcntl.h /usr/include/features.h /usr/include/sys/cdefs.h \
+  /usr/include/sys/types.h /usr/include/linux/types.h /usr/include/linux/fcntl.h \
+  /usr/include/getopt.h /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \
+  /usr/include/stdlib.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stddef.h /usr/include/errno.h \
+  /usr/include/linux/errno.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/float.h \
+  /usr/include/string.h /usr/include/time.h /usr/include/unistd.h /usr/include/posix_opt.h \
+  /usr/include/gnu/types.h /usr/include/linux/ext2_fs.h ../lib/ext2fs/ext2fs.h \
+  ../lib/et/com_err.h /usr/lib/gcc-lib/i486-linux/2.5.8/include/stdarg.h ../lib/ext2fs/io.h \
+  ../lib/ext2fs/ext2_err.h ../lib/ext2fs/bitops.h ../lib/e2p/e2p.h /usr/include/dirent.h \
+  /usr/include/linux/limits.h /usr/include/linux/dirent.h ../version.h 
diff --git a/misc/Makefile b/misc/Makefile
new file mode 100644 (file)
index 0000000..3b37dc7
--- /dev/null
@@ -0,0 +1,73 @@
+include ../MCONFIG
+
+CFLAGS=                $(OPT) $(WFLAGS) -I../lib
+LDFLAGS=       $(OPT)
+SPROGS=                tune2fs mklost+found mke2fs dumpe2fs badblocks fsck
+SMANPAGES=     tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
+                       fsck.8
+
+UPROGS=                chattr lsattr
+UMANPAGES=     chattr.1 lsattr.1
+
+TUNE2FS_OBJS=  tune2fs.o
+MKLPF_OBJS=    mklost+found.o
+MKE2FS_OBJS=   mke2fs.o
+CHATTR_OBJS=   chattr.o
+LSATTR_OBJS=   lsattr.o
+DUMPE2FS_OBJS= dumpe2fs.o
+BADBLOCKS_OBJS=        badblocks.o
+FSCK_OBJS=     fsck.o
+
+LIBS= -L../lib -lext2fs -le2p -lcom_err 
+DEPLIBS= ../lib/libext2fs.a ../lib/libe2p.a ../lib/libcom_err.a 
+
+all: $(SPROGS) $(UPROGS)
+
+tune2fs: $(TUNE2FS_OBJS) $(DEPLIBS)
+       cc $(LDFLAGS) -o tune2fs $(TUNE2FS_OBJS) $(LIBS)
+
+mklost+found: $(MKLPF_OBJS)
+       cc $(LDFLAGS) -o mklost+found $(MKLPF_OBJS)
+
+mke2fs: $(MKE2FS_OBJS) $(DEPLIBS)
+       cc $(LDFLAGS) -o mke2fs $(MKE2FS_OBJS) $(LIBS)
+
+chattr: $(CHATTR_OBJS) $(DEPLIBS)
+       cc $(LDFLAGS) -o chattr $(CHATTR_OBJS) $(LIBS)
+
+lsattr: $(LSATTR_OBJS) $(DEPLIBS)
+       cc $(LDFLAGS) -o lsattr $(LSATTR_OBJS) $(LIBS)
+
+dumpe2fs: $(DUMPE2FS_OBJS) $(DEPLIBS)
+       cc $(LDFLAGS) -o dumpe2fs $(DUMPE2FS_OBJS) $(LIBS)
+
+badblocks: $(BADBLOCKS_OBJS) $(DEPLIBS)
+       cc $(LDFLAGS) -o badblocks $(BADBLOCKS_OBJS) $(LIBS)
+
+install:: $(SPROGS) $(UPROGS)
+       for i in $(SPROGS); do \
+               $(INSTALLBIN) $$i $(SBINDIR)/$$i; \
+       done
+       ln -sf mke2fs $(SBINDIR)/mkfs.ext2
+       for i in $(UPROGS); do \
+               $(INSTALLBIN) $$i $(USRBINDIR)/$$i; \
+       done
+
+install:: $(SMANPAGES) $(UMANPAGES)
+       for i in $(SMANPAGES); do \
+               $(INSTALLMAN) $$i $(SMANDIR)/$$i; \
+       done
+       for i in $(UMANPAGES); do \
+               $(INSTALLMAN) $$i $(UMANDIR)/$$i; \
+       done
+
+clean:
+       rm -f $(SPROGS) $(UPROGS) \#* *.s *.o *.a *~ core
+
+really-clean: clean
+       rm -f .depend 
+
+dep depend .depend:
+       $(CPP) $(CFLAGS) -M *.c >.depend
+
+include .depend
diff --git a/misc/badblocks.8 b/misc/badblocks.8
new file mode 100644 (file)
index 0000000..080ca5b
--- /dev/null
@@ -0,0 +1,66 @@
+.\" -*- nroff -*-
+.TH BADBLOCKS 8 "March 1994" "Version 0.5"
+.SH NAME
+badblocks \- search a device for bad blocks
+.SH SYNOPSIS
+.B badblocks
+[
+.B \-b
+block-size
+]
+[
+.B \-o
+output_file
+]
+[
+.B \-v
+]
+[
+.B \-w
+]
+device
+blocks-count
+.SH DESCRIPTION
+.B badblocks
+is used to search for bad blocks on a device (usually a disk partition).
+.br
+.I device
+is the special file corresponding to the device (e.g /dev/hdXX).
+.br
+.I blocks-count
+is the number of blocks on the device.
+.SH OPTIONS
+.TP
+.I -b block-size
+Specify the size of blocks in bytes.
+.TP
+.I -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.
+.TP
+.I -v
+Verbose mode.
+.TP
+.I -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.
+.SH WARNING
+Never use the `-w' option on an device containing an existing file system.
+This option erases data!
+.SH AUTHOR
+.B badblocks
+has been written by Remy Card <card@masi.ibp.fr>, the developer and maintainer
+of the ext2 fs.
+.SH BUGS
+I had no chance to make reals tests of this program since I use IDE drives
+which remap bad blocks. I only made some tests on floppies.
+.SH AVAILABILITY
+.B badblocks
+is available for anonymous ftp from ftp.ibp.fr (132.227.60.2) in
+/pub/linux/BETA/ext2fs.
+.SH SEE ALSO
+.BR e2fsck (8),
+.BR mke2fs (8)
diff --git a/misc/badblocks.c b/misc/badblocks.c
new file mode 100644 (file)
index 0000000..0560e67
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * 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)
+ *
+ * This file is based on the minix file system programs fsck and mkfs
+ * written and copyrighted by Linus Torvalds <Linus.Torvalds@cs.helsinki.fi>
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+/*
+ * History:
+ * 93/05/26    - Creation from e2fsck
+ * 94/02/27    - Made a separate bad blocks checker
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+
+#include <linux/fd.h>
+#include <linux/fs.h>
+
+#include "et/com_err.h"
+
+const char * program_name = "badblocks";
+
+int v_flag = 0;                        /* verbose */
+int w_flag = 0;                        /* do r/w test */
+int s_flag = 0;                        /* show progress of test */
+
+static volatile void usage (void)
+{
+       fprintf (stderr, "Usage: %s [-b block_size] [-o output_file] [-w] device blocks_count\n",
+                program_name);
+       exit (1);
+}
+
+/*
+ * Perform a test of a block; return the number of blocks readable/writeable.
+ */
+static long do_test (int dev, char * buffer, int try, unsigned long block_size,
+                    unsigned long current_block)
+{
+       long got;
+
+       /* Seek to the correct loc. */
+       if (lseek (dev, current_block * block_size, SEEK_SET) !=
+           current_block * block_size)
+                 com_err (program_name, errno, "during seek");
+
+       /* Try the read */
+       got = read (dev, buffer, try * block_size);
+       if (got < 0)
+               got = 0;        
+       if (got & (block_size - 1))
+               fprintf (stderr, "Weird values in do_test: probably bugs\n");
+       got /= block_size;
+       return got;
+}
+
+static unsigned long currently_testing = 0;
+static unsigned long num_blocks = 0;
+
+static void alarm_intr (int alnum)
+{
+       signal (SIGALRM, alarm_intr);
+       alarm(1);
+       if (!num_blocks)
+               return;
+       fprintf(stderr, "%6ld/%6ld", currently_testing, num_blocks);
+       fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b");
+       fflush (stderr);
+}
+
+static void test_ro (int dev, unsigned long blocks_count,
+                    unsigned long block_size, FILE * out)
+{
+#define TEST_BUFFER_BLOCKS 16
+       char * blkbuf;
+       int try;
+       long got;
+
+       blkbuf = malloc (TEST_BUFFER_BLOCKS * block_size);
+       if (!blkbuf)
+       {
+               com_err (program_name, ENOMEM, "while allocating buffers");
+               exit (1);
+       }
+
+       if (v_flag)
+               fprintf (stderr, "Flushing buffers\n");
+       ioctl (dev, BLKFLSBUF, 0);      /* In case this is a HD */
+       ioctl (dev, FDFLUSH, 0);        /* In case this is floppy */
+       if (v_flag) 
+               fprintf (stderr,
+                        "Checking for bad blocks in read-only mode\n");
+       try = TEST_BUFFER_BLOCKS;
+       currently_testing = 0;
+       num_blocks = blocks_count;
+       if (s_flag) {
+               fprintf(stderr, "Checking for bad blocks (read-only test): ");
+               alarm_intr(SIGALRM);
+       }
+       while (currently_testing < blocks_count)
+       {
+               if (currently_testing + try > blocks_count)
+                       try = blocks_count - currently_testing;
+               got = do_test (dev, blkbuf, try, block_size, currently_testing);
+               currently_testing += got;
+               if (got == try) {
+                       try = TEST_BUFFER_BLOCKS;
+                       continue;
+               }
+               else
+                       try = 1;
+               if (got == 0)
+                       fprintf (out, "%lu\n", currently_testing++);
+       }
+       num_blocks = 0;
+       alarm(0);
+       if (s_flag)
+               fprintf(stderr, "done         \n");
+       free (blkbuf);
+}
+
+static void test_rw (int dev, unsigned long blocks_count,
+                    unsigned long block_size, FILE * out)
+{
+       int i;
+       int j;
+       char * buffer;
+       unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00};
+
+       buffer = malloc (2 * block_size);
+       if (!buffer)
+       {
+               com_err (program_name, ENOMEM, "while allocating buffers");
+               exit (1);
+       }
+
+       if (v_flag)
+               fprintf (stderr, "Flushing buffers\n");
+       ioctl (dev, BLKFLSBUF, 0);      /* In case this is a HD */
+       ioctl (dev, FDFLUSH, 0);        /* In case this is floppy */
+       if (v_flag)
+               fprintf (stderr, "Checking for bad blocks in read-write mode\n");
+       for (i = 0; i < sizeof (pattern); i++)
+       {
+               memset (buffer, pattern[i], block_size);
+               if (v_flag)
+                       fprintf (stderr, "Writing pattern 0x%08x\n",
+                                *((int *) buffer));
+               for (j = 0; j < blocks_count; j++)
+               {
+                       if (lseek (dev, j * block_size, SEEK_SET) != j * block_size)
+                               com_err (program_name, errno,
+                                        "during seek on block %d", j);
+                       write (dev, buffer, block_size);
+               }
+               if (v_flag)
+                       fprintf (stderr, "Flushing buffers\n");
+               if (fsync (dev) == -1)
+                       com_err (program_name, errno, "during fsync");
+               ioctl (dev, BLKFLSBUF, 0);      /* In case this is a HD */
+               ioctl (dev, FDFLUSH, 0);        /* In case this is floppy */
+               if (v_flag)
+                       fprintf (stderr, "Reading and comparing\n");
+               for (j = 0; j < blocks_count; j++)
+               {
+                       if (lseek (dev, j * block_size, SEEK_SET) != j * block_size)
+                               com_err (program_name, errno,
+                                        "during seek on block %d", j);
+                       if (read (dev, buffer + block_size, block_size) < block_size)
+                               fprintf (out, "%d\n", j);
+                       else if (memcmp (buffer, buffer + block_size, block_size))
+                               fprintf (out, "%d\n", j);
+                               
+               }
+               if (v_flag)
+                       fprintf (stderr, "Flushing buffers\n");
+               ioctl (dev, BLKFLSBUF, 0);      /* In case this is a HD */
+               ioctl (dev, FDFLUSH, 0);        /* In case this is floppy */
+       }
+}
+
+void main (int argc, char ** argv)
+{
+       char c;
+       char * tmp;
+       char * device_name;
+       char * output_file = NULL;
+       FILE * out;
+       unsigned long block_size = 1024;
+       unsigned long blocks_count;
+       int dev;
+
+       setbuf(stdout, NULL);
+       setbuf(stderr, NULL);
+       if (argc && *argv)
+               program_name = *argv;
+       while ((c = getopt (argc, argv, "b:o:svw")) != EOF) {
+               switch (c) {
+               case 'b':
+                       block_size = strtoul (optarg, &tmp, 0);
+                       if (*tmp || block_size > 4096) {
+                               com_err (program_name, 0,
+                                        "bad block size - %s", optarg);
+                               exit (1);
+                       }
+                       break;
+               case 'o':
+                       output_file = optarg;
+                       break;
+               case 's':
+                       s_flag = 1;
+                       break;
+               case 'v':
+                       v_flag = 1;
+                       break;
+               case 'w':
+                       w_flag = 1;
+                       break;
+               default:
+                       usage ();
+               }
+       }
+       if (optind > argc - 1)
+               usage ();
+       device_name = argv[optind++];
+       if (optind > argc - 1)
+               usage ();
+       blocks_count = strtoul (argv[optind], &tmp, 0);
+       if (*tmp)
+       {
+               com_err (program_name, 0, "bad blocks count - %s", argv[optind]);
+               exit (1);
+       }
+       dev = open (device_name, w_flag ? O_RDWR : O_RDONLY);
+       if (dev == -1)
+       {
+               com_err (program_name, errno,"while trying to open %s",
+                        device_name);
+               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",
+                                device_name);
+                       exit (1);
+               }
+       }
+       else
+               out = stdout;
+       if (w_flag)
+               test_rw (dev, blocks_count, block_size, out);
+       else
+               test_ro (dev, blocks_count, block_size, out);
+       close (dev);
+       if (out != stdout)
+               fclose (out);
+}
diff --git a/misc/chattr.1 b/misc/chattr.1
new file mode 100644 (file)
index 0000000..6a8e119
--- /dev/null
@@ -0,0 +1,57 @@
+.\" -*- nroff -*-
+.TH CHATTR 1 "March 1994" "Version 0.5"
+.SH NAME
+chattr \- change file attributes on a Linux second extended file system
+.SH SYNOPSIS
+.B chattr
+[
+.B \-RV
+]
+[
+.B -v
+version
+]
+[
+mode
+]
+.I files...
+.SH DESCRIPTION
+.B chattr
+changes the files attributes on an second extended file system.
+.PP
+The format of a symbolic mode is +-=[Scsu].
+.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 `Scsu' select the new attributes for the files: synchronous
+updates (S), compressed (c), secure deletion (s), and undeletable (u).
+.SH OPTIONS
+.TP
+.I -R
+Recursively change attributes of directories and their contents.
+.TP
+.I -V
+Verbosely describe changed attributes.
+.TP
+.I -v version
+Set the files version.
+.SH AUTHOR
+.B chattr
+has been written by Remy Card <card@masi.ibp.fr>, the developer and maintainer
+of the ext2 fs.
+.SH BUGS AND LIMITATIONS
+As of ext2 fs 0.4, the kernel code only honours the `s' and `S' attributes. When
+a file with the `s' attribute set is deleted, its blocks are zeroed and
+written back to the disk. 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
+The other attributes will be implemented in a next ext2 fs version.
+.SH AVAILABILITY
+.B chattr
+is available for anonymous ftp from ftp.ibp.fr (132.227.60.2) in
+/pub/linux/BETA/ext2fs.
+.SH SEE ALSO
+.BR lsattr (1)
diff --git a/misc/chattr.c b/misc/chattr.c
new file mode 100644 (file)
index 0000000..63c8108
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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
+ */
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <linux/ext2_fs.h>
+
+#include "et/com_err.h"
+#include "e2p/e2p.h"
+
+#include "../version.h"
+
+const char * program_name = "chattr";
+
+int add = 0;
+int rem = 0;
+int set = 0;
+int set_version = 0;
+
+unsigned long version;
+
+int recursive = 0;
+int verbose = 0;
+
+unsigned long af;
+unsigned long rf;
+unsigned long sf;
+
+static void volatile fatal_error (const char * fmt_string, int errcode)
+{
+       fprintf (stderr, fmt_string, program_name);
+       exit (errcode);
+}
+
+#define usage() fatal_error ("usage: %s [-RV] [-+=csu] [-v version] files...\n", \
+                            1)
+
+static int decode_arg (int * i, int argc, char ** argv)
+{
+       char * p;
+       char * tmp;
+
+       switch (argv[*i][0])
+       {
+       case '-':
+               for (p = &argv[*i][1]; *p; p++)
+                       switch (*p)
+                       {
+                       case 'R':
+                               recursive = 1;
+                               break;
+                       case 'S':
+                               rf |= EXT2_SYNC_FL;
+                               rem = 1;
+                               break;
+                       case 'V':
+                               verbose = 1;
+                               break;
+                       case 'c':
+                               rf |= EXT2_COMPR_FL;
+                               rem = 1;
+                               break;
+                       case 's':
+                               rf |= EXT2_SECRM_FL;
+                               rem = 1;
+                               break;
+                       case 'u':
+                               rf |= EXT2_UNRM_FL;
+                               rem = 1;
+                               break;
+                       case 'v':
+                               if (*i >= argc)
+                                       usage ();
+                               (*i)++;
+                               version = strtol (argv[*i], &tmp, 0);
+                               if (*tmp)
+                               {
+                                       com_err (program_name, 0,
+                                                "bad version - %s\n", argv[*i]);
+                                       usage ();
+                               }
+                               set_version = 1;
+                               break;
+                       default:
+                               fprintf (stderr, "%s: Unrecognized argument: %c\n",
+                                        program_name, *p);
+                               usage ();
+                       }
+               break;
+       case '+':
+               add = 1;
+               for (p = &argv[*i][1]; *p; p++)
+                       switch (*p)
+                       {
+                       case 'S':
+                               af |= EXT2_SYNC_FL;
+                               break;
+                       case 'c':
+                               af |= EXT2_COMPR_FL;
+                               break;
+                       case 's':
+                               af |= EXT2_SECRM_FL;
+                               break;
+                       case 'u':
+                               af |= EXT2_UNRM_FL;
+                               break;
+                       default:
+                               usage ();
+                       }
+               break;
+       case '=':
+               set = 1;
+               for (p = &argv[*i][1]; *p; p++)
+                       switch (*p)
+                       {
+                       case 'S':
+                               sf |= EXT2_SYNC_FL;
+                               break;
+                       case 'c':
+                               sf |= EXT2_COMPR_FL;
+                               break;
+                       case 's':
+                               sf |= EXT2_SECRM_FL;
+                               break;
+                       case 'u':
+                               sf |= EXT2_UNRM_FL;
+                               break;
+                       default:
+                               usage ();
+                       }
+               break;
+       default:
+               return EOF;
+               break;
+       }
+       return 1;
+}
+
+static int chattr_dir_proc (const char *, struct dirent *, void *);
+
+static void change_attributes (const char * name)
+{
+       unsigned long flags;
+       struct stat st;
+
+       if (lstat (name, &st) == -1)
+       {
+               com_err (program_name, errno, "while stating %s", name);
+               return;
+       }
+       if (set)
+       {
+               if (verbose)
+               {
+                       printf ("Flags of %s set as ", name);
+                       print_flags (stdout, sf);
+                       printf ("\n");
+               }
+               if (fsetflags (name, sf) == -1)
+                       perror (name);
+       }
+       else
+       {
+               if (fgetflags (name, &flags) == -1)
+                       com_err (program_name, errno,
+                                "while reading flags on %s", name);
+               else
+               {
+                       if (rem)
+                               flags &= ~rf;
+                       if (add)
+                               flags |= af;
+                       if (verbose)
+                       {
+                               printf ("Flags of %s set as ", name);
+                               print_flags (stdout, flags);
+                               printf ("\n");
+                       }
+                       if (fsetflags (name, flags) == -1)
+                               com_err (program_name, errno,
+                                        "while setting flags on %s", name);
+               }
+       }
+       if (set_version)
+       {
+               if (verbose)
+                       printf ("Version of %s set as %lu\n", name, version);
+               if (fsetversion (name, version) == -1)
+                       com_err (program_name, errno,
+                                "while setting version on %s", name);
+       }
+       if (S_ISDIR(st.st_mode) && recursive)
+               iterate_on_dir (name, chattr_dir_proc, (void *) NULL);
+}
+
+static int chattr_dir_proc (const char * dir_name, struct dirent * de, void * private)
+{
+       char path[MAXPATHLEN];
+
+       if (strcmp (de->d_name, ".") && strcmp (de->d_name, ".."))
+       {
+               sprintf (path, "%s/%s", dir_name, de->d_name);
+               change_attributes (path);
+       }
+       return 0;
+}
+
+void main (int argc, char ** argv)
+{
+       int i, j;
+       int end_arg = 0;
+
+       fprintf (stderr, "chattr %s, %s for EXT2 FS %s, %s\n",
+                E2FSPROGS_VERSION, E2FSPROGS_DATE,
+                EXT2FS_VERSION, EXT2FS_DATE);
+       if (argc && *argv)
+               program_name = *argv;
+       i = 1;
+       while (i < argc && !end_arg)
+       {
+               if (decode_arg (&i, argc, argv) == EOF)
+                       end_arg = 1;
+               else
+                       i++;
+       }
+       if (i >= argc)
+               usage ();
+       if (set && (add || rem))
+       {
+               fprintf (stderr, "= is incompatible with - and +\n");
+               exit (1);
+       }
+       if (!(add || rem || set))
+       {
+               fprintf (stderr, "Must use =, - or +\n");
+               exit (1);
+       }
+       for (j = i; j < argc; j++)
+               change_attributes (argv[j]);
+}
diff --git a/misc/dumpe2fs.8 b/misc/dumpe2fs.8
new file mode 100644 (file)
index 0000000..30a90b5
--- /dev/null
@@ -0,0 +1,32 @@
+.TH DUMPE2FS 8 "March 1994" "Version 0.5"
+
+.SH NAME
+dumpe2fs \- dump filesystem information
+.SH SYNOPSIS
+.B dumpe2fs
+device
+.SH DESCRIPTION
+.BI dumpe2fs
+prints the super block and blocks group information for the filesystem
+present on
+.I device.
+.PP
+.BI dumpe2fs
+is similar to Berkeley's
+.BI dumpfs
+program for the BSD Fast File System.
+.SH BUGS
+You need to know the physical filesystem structure to understand the
+output.
+.SH AUTHOR
+.B dumpe2fs 
+has been written by Remy Card <card@masi.ibp.fr>, the developer and maintainer
+of the ext2 fs.
+.SH AVAILABILITY
+.B dumpe2fs
+is available for anonymous ftp from ftp.ibp.fr (132.227.60.2) in
+/pub/linux/BETA/ext2fs.
+.SH SEE ALSO
+.BR e2fsck (8),
+.BR mke2fs (8),
+.BR tune2fs (8)
diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
new file mode 100644 (file)
index 0000000..fc0c45b
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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)
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+/*
+ * History:
+ * 94/01/09    - Creation
+ * 94/02/27    - Ported to use the ext2fs library
+ */
+
+#include <getopt.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/ext2_fs.h>
+
+#include "ext2fs/ext2fs.h"
+#include "e2p/e2p.h"
+
+#include "../version.h"
+
+#define in_use(m, x)   (test_bit ((x), (m)))
+
+const char * program_name = "dumpe2fs";
+char * device_name = NULL;
+
+static volatile void usage (void)
+{
+       fprintf (stderr, "usage: %s device\n", program_name);
+       exit (1);
+}
+
+static void print_free (unsigned long group, char * bitmap,
+                       unsigned long nbytes, unsigned long offset)
+{
+       int p = 0;
+       unsigned long i;
+       unsigned long j;
+
+       for (i = 0; i < nbytes; i++)
+               if (!in_use (bitmap, i))
+               {
+                       if (p)
+                               printf (", ");
+                       if (i == nbytes - 1 || in_use (bitmap, i + 1))
+                               printf ("%lu", group * nbytes + i + offset);
+                       else
+                       {
+                               for (j = i; j < nbytes && !in_use (bitmap, j);
+                                    j++)
+                                       ;
+                               printf ("%lu-%lu", group * nbytes + i + offset,
+                                       group * nbytes + (j - 1) + offset);
+                               i = j - 1;
+                       }
+                       p = 1;
+               }
+}
+
+static void list_desc (ext2_filsys fs)
+{
+       unsigned long i;
+       char * block_bitmap = fs->block_map;
+       char * inode_bitmap = fs->inode_map;
+
+       printf ("\n");
+       for (i = 0; i < fs->group_desc_count; i++)
+       {
+               printf ("Group %lu:\n", i);
+               printf ("  Block bitmap at %lu, Inode bitmap at %lu, "
+                       "Inode table at %lu\n",
+                       fs->group_desc[i].bg_block_bitmap,
+                       fs->group_desc[i].bg_inode_bitmap,
+                       fs->group_desc[i].bg_inode_table);
+               printf ("  %d free blocks, %d free inodes, %d directories\n",
+                       fs->group_desc[i].bg_free_blocks_count,
+                       fs->group_desc[i].bg_free_inodes_count,
+                       fs->group_desc[i].bg_used_dirs_count);
+               printf ("  Free blocks: ");
+               print_free (i, block_bitmap, fs->super->s_blocks_per_group,
+                           fs->super->s_first_data_block);
+               block_bitmap += fs->super->s_blocks_per_group / 8;
+               printf ("\n");
+               printf ("  Free inodes: ");
+               print_free (i, inode_bitmap, fs->super->s_inodes_per_group, 1);
+               inode_bitmap += fs->super->s_inodes_per_group / 8;
+               printf ("\n");
+       }
+}
+
+static void list_bad_blocks(ext2_filsys fs)
+{
+       badblocks_list          bb_list = 0;
+       badblocks_iterate       bb_iter;
+       blk_t                   blk;
+       errcode_t               retval;
+
+       retval = ext2fs_read_bb_inode(fs, &bb_list);
+       if (retval) {
+               com_err("ext2fs_read_bb_inode", retval, "");
+               exit(1);
+       }
+       retval = badblocks_list_iterate_begin(bb_list, &bb_iter);
+       if (retval) {
+               com_err("badblocks_list_iterate_begin", retval,
+                       "while printing bad block list");
+               exit(1);
+       }
+       if (badblocks_list_iterate(bb_iter, &blk))
+               printf("Bad blocks: %ld", blk);
+       while (badblocks_list_iterate(bb_iter, &blk))
+               printf(", %ld", blk);
+       badblocks_list_iterate_end(bb_iter);
+       printf("\n");
+}
+
+void main (int argc, char ** argv)
+{
+       errcode_t       retval;
+       ext2_filsys     fs;
+
+       fprintf (stderr, "dumpe2fs %s, %s for EXT2 FS %s, %s\n",
+                E2FSPROGS_VERSION, E2FSPROGS_DATE,
+                EXT2FS_VERSION, EXT2FS_DATE);
+       if (argc && *argv)
+               program_name = *argv;
+       if (argc != 2)
+               usage ();
+       device_name = argv[1];
+       retval = ext2fs_open (device_name, 0, 0, 0, unix_io_manager, &fs);
+       if (retval)
+       {
+               com_err (program_name, retval, "while trying to open %s",
+                        device_name);
+               printf ("Couldn't find valid filesystem superblock.\n");
+               exit (1);
+       }
+       retval = ext2fs_read_bitmaps (fs);
+       if (retval)
+       {
+               com_err (program_name, retval, "while trying to read the bitmaps",
+                        device_name);
+               ext2fs_close (fs);
+               exit (1);
+       }
+       list_super (fs->super);
+       list_bad_blocks (fs);
+       list_desc (fs);
+       ext2fs_close (fs);
+       exit (0);
+}
diff --git a/misc/fsck.8 b/misc/fsck.8
new file mode 100644 (file)
index 0000000..620a7fc
--- /dev/null
@@ -0,0 +1,152 @@
+.\" -*- nroff -*-
+.TH FSCK 8 "Mar 1994" "Version 0.5"
+.SH NAME
+fsck \- check and repair a Linux file system
+.SH SYNOPSIS
+.B fsck
+[
+.B \-A
+]
+[
+.B \-V
+]
+[
+.B \-t
+.I fstype
+]
+[
+.B fs-options
+]
+.I filesys [ ... ]
+.SH DESCRIPTION
+.B fsck
+is used to check and optionally repair a Linux file system.  
+.I filesys
+is either the device name (e.g. /dev/hda1, /dev/sdb2) or the mount point
+(e.g. /, /usr, /home) for the file system.  If this fsck has several
+filesystems on different physical disk drives to check, this fsck will
+try to run them in parallel.  This reduces the total amount time it
+takes to check all of the filesystems, since fsck takes advantage of the
+parallelism of multiple disk spindles.
+.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
+\      128\    \-\ Shared library error
+.br
+The exit code returned when all file systems are checked using the
+.B -A
+option 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 /sbin first, then in /etc/fs
+and /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 -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 initalization file, instead of multiple commands for checking
+a single file system.  Note, that with this option, you cannot give
+the
+.I filesys
+argument as well.
+.TP
+.B -s
+Serialize fsck operations.  This is a good idea if you checking multiple
+filesystems in and the checkers are in an interactive mode.  (Note:
+.B e2fsck
+runs in an interactive mode by default.  To make 
+.B e2fsck
+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
+.B -V
+Produce verbose output, including all file system-specific commands
+that are executed.
+Specifying this option more than once inhibits execution of any
+file system-specific commands.
+This is really only useful for testing.
+.TP
+.BI -t \ fstype
+Specifies the type of file system to be checked.
+If not specified, the type is deduced by searching for
+.I filesys
+in
+.I /etc/fstab
+and using the corresponding entry.
+If the type can not be deduced, the default file system type
+(currently ext2) is used.
+.TP
+.B fs-options
+Any options which are not understood by 
+.BR fsck ,
+or which follow the
+.B --
+option are treated as file system-specific options to be passed to the
+realm file system checker.
+.PP
+Currently, standardized file system-specific options are somewhat in
+flux.  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 
+.B e2fsck
+supports 
+.B -a
+for backwards compatibility only.  This option is mapped to e2fsck's
+.B -p
+option which is safe to use, unlike the 
+.B -a 
+option that most file system checkers support.
+.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 
+.B e2fsck
+default behavior; it supports this option for backwards compatibility
+reasons only.
+.SH AUTHOR
+Theodore Ts'o (tytso@mit.edu)
+.PP
+The manual page was shamelessly adapted from David Engel and Fred van
+Kempen's generic fsck front end program, which was in turn shamelessly
+adapted from Remy Card's version for the ext2 file system.
+.SH SEE ALSO
+.BR mkfs (8),
+.BR fsck.minix (8),
+.BR fsck.ext2 (8)
+or
+.BR e2fsck (8),
+.BR fsck.xiafs (8).
diff --git a/misc/fsck.c b/misc/fsck.c
new file mode 100644 (file)
index 0000000..eb01fc5
--- /dev/null
@@ -0,0 +1,576 @@
+/*
+ * 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>
+ * 
+ * Usage:      fsck [-AV] [-t fstype] [fs-options] device
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
+ * redistributed under the terms of the GNU Public License.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <mntent.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "../version.h"
+#include "fsck.h"
+
+static const char *ignored_types[] = {
+       "ignore",
+       "iso9660",
+       "msdos",
+       "nfs",
+       "proc",
+       "sw",
+       "swap",
+       NULL
+};
+
+static const char *base_devices[] = {
+       "/dev/hda",
+       "/dev/hdb",
+       "/dev/hdc",
+       "/dev/hdd",
+       "/dev/sda",
+       "/dev/sdb",
+       "/dev/sdc",
+       "/dev/sdd",
+       "/dev/sde",
+       "/dev/sdf",
+       "/dev/sdg",
+       NULL
+};
+
+/*
+ * Global variables for options
+ */
+char *devices[MAX_DEVICES];
+char *args[MAX_ARGS];
+int num_devices, num_args;
+
+int verbose = 0;
+int doall = 0;
+int noexecute = 0;
+int serialize = 0;
+char *progname;
+char *fstype = NULL;
+struct fs_info *filesys_info;
+struct fsck_instance *instance_list;
+
+static char *strdup(char *s)
+{
+       char    *ret;
+
+       ret = malloc(strlen(s)+1);
+       if (ret)
+               strcpy(ret, s);
+       return ret;
+}
+
+static void free_instance(struct fsck_instance *i)
+{
+       if (i->prog)
+               free(i->prog);
+       if (i->device)
+               free(i->device);
+       free(i);
+       return;
+}
+
+/*
+ * Load the filesystem database from /etc/fstab
+ */
+static void load_fs_info(NOARGS)
+{
+       FILE *mntfile;
+       struct mntent *mp;
+       struct fs_info *fs;
+
+       filesys_info = NULL;
+       
+       /* Open the mount table. */
+       if ((mntfile = setmntent(MNTTAB, "r")) == NULL) {
+               perror(MNTTAB);
+               exit(EXIT_ERROR);
+       }
+
+       while ((mp = getmntent(mntfile)) != NULL) {
+               fs = malloc(sizeof(struct fs_info));
+               memset(fs, 0, sizeof(struct fs_info));
+               fs->device = strdup(mp->mnt_fsname);
+               fs->mountpt = strdup(mp->mnt_dir);
+               fs->type = strdup(mp->mnt_type);
+               fs->opts = strdup(mp->mnt_opts);
+               fs->freq = mp->mnt_freq;
+               fs->passno = mp->mnt_passno;
+               fs->next = filesys_info;
+               filesys_info = fs;
+       }
+
+       (void) endmntent(mntfile);
+}
+       
+/* 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) ||
+                   !strcmp(filesys, fs->mountpt))
+                       break;
+       }
+
+       return fs;
+}
+
+/*
+ * Execute a particular fsck program, and link it into the list of
+ * child processes we are waiting for.
+ */
+static int execute(char *prog, char *device)
+{
+       char *argv[80];
+       int  argc, i;
+       struct fsck_instance *inst;
+       pid_t   pid;
+
+       argv[0] = strdup(prog);
+       argc = 1;
+       
+       for (i=0; i <num_args; i++)
+               argv[argc++] = strdup(args[i]);
+
+       argv[argc++] = strdup(device);
+       argv[argc] = 0;
+
+       if (verbose || noexecute) {
+               for (i=0; i < argc; i++)
+                       printf("%s ", argv[i]);
+               printf("\n");
+       }
+       if (noexecute)
+               return 0;
+       
+       /* Fork and execute the correct program. */
+       if ((pid = fork()) < 0) {
+               perror("fork");
+               return errno;
+       } else if (pid == 0) {
+               (void) execvp(prog, argv);
+               perror(args[0]);
+               exit(EXIT_ERROR);
+       }
+       inst = malloc(sizeof(struct fsck_instance));
+       if (!inst)
+               return ENOMEM;
+       memset(inst, 0, sizeof(struct fsck_instance));
+       inst->pid = pid;
+       inst->prog = strdup(prog);
+       inst->device = strdup(device);
+       inst->next = instance_list;
+       instance_list = inst;
+       
+       return 0;
+}
+
+/*
+ * 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(NOARGS)
+{
+       int     status;
+       struct fsck_instance *inst, *prev;
+       pid_t   pid;
+
+       if (!instance_list)
+               return NULL;
+
+retry:
+       pid = wait(&status);
+       status = WEXITSTATUS(status);
+       if (pid < 0) {
+               if ((errno == EINTR) || (errno == EAGAIN))
+                       goto retry;
+               if (errno == ECHILD) {
+                       fprintf(stderr,
+                               "%s: wait: No more child process?!?\n",
+                               progname);
+                       return NULL;
+               }
+               perror("wait");
+               goto retry;
+       }
+       for (prev = 0, inst = instance_list;
+            inst;
+            prev = inst, inst = inst->next) {
+               if (inst->pid == pid)
+                       break;
+       }
+       if (!inst) {
+               printf("Unexpected child process %d, status = 0x%x\n",
+                      pid, status);
+               goto retry;
+       }
+       
+       inst->exit_status = status;
+       if (prev)
+               prev->next = inst->next;
+       else
+               instance_list = inst->next;
+       return inst;
+}
+
+/*
+ * Wait until all executing child processes have exited; return the
+ * logical OR of all of their exit code values.
+ */
+static int wait_all(NOARGS)
+{
+       struct fsck_instance *inst;
+       int     global_status = 0;
+
+       while (instance_list) {
+               inst = wait_one();
+               if (!inst)
+                       break;
+               global_status |= inst->exit_status;
+               free_instance(inst);
+       }
+       return global_status;
+}
+
+/*
+ * Run the fsck program on a particular device
+ */
+static void fsck_device(char *device)
+{
+       const char      *type;
+       struct fs_info *fsent;
+       int retval;
+       char prog[80];
+
+       if (fstype)
+               type = fstype;
+       else if ((fsent = lookup(device))) {
+               device = fsent->device;
+               type = fsent->type;
+       } else
+               type = DEFAULT_FSTYPE;
+
+       sprintf(prog, "fsck.%s", type);
+       retval = execute(prog, device);
+       if (retval) {
+               fprintf(stderr, "%s: Error %d while executing %s for %s\n",
+                       progname, retval, prog, device);
+       }
+}
+
+/* Check if we should ignore this filesystem. */
+static int ignore(struct fs_info *fs)
+{
+       const char *cp;
+       const char **ip;
+
+       /*
+        * If a specific fstype is specified, and it doesn't match,
+        * ignore it.
+        */
+       if (fstype && strcmp(fstype, fs->type))
+               return 1;
+       
+       ip = ignored_types;
+       while (*ip != NULL) {
+               if (!strcmp(fs->type, *ip))
+                       return 1;
+               ip++;
+       }
+
+       for (cp = strtok(fs->opts, ","); cp != NULL; cp = strtok(NULL, ",")) {
+               if (!strcmp(cp, "noauto"))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * 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.
+ */
+static const char *base_device(char *device)
+{
+       const char **base;
+
+       for (base = base_devices; *base; base++) {
+               if (!strncmp(*base, device, strlen(*base)))
+                       return *base;
+               base++;
+       }
+       return device;
+}
+
+/*
+ * Returns TRUE if a partition on the same disk is already being
+ * checked.
+ */
+static int device_already_active(char *device)
+{
+       struct fsck_instance *inst;
+       const char *base;
+
+       base = base_device(device);
+
+       for (inst = instance_list; inst; inst = inst->next) {
+               if (!strcmp(base, base_device(inst->device)))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/* Check all file systems, using the /etc/fstab table. */
+static int check_all(NOARGS)
+{
+       struct fs_info *fs;
+       struct fsck_instance *inst;
+       int status = EXIT_OK;
+       int not_done_yet = 1;
+       int passno = 0;
+       int pass_done;
+
+       if (verbose)
+               printf("Checking all file systems.\n");
+
+       /*
+        * Find and check the root filesystem first.
+        */
+       for (fs = filesys_info; fs; fs = fs->next) {
+               if (!strcmp(fs->mountpt, "/"))
+                       break;
+       }
+       if (fs &&
+           (!fstype || !strcmp(fstype, fs->type))) {
+               fsck_device(fs->device);
+               fs->flags |= FLAG_DONE;
+               status |= wait_all();
+               if (status > EXIT_NONDESTRUCT)
+                       return status;
+       }
+
+       /*
+        * Mark filesystems that should be ignored as done.
+        */
+       for (fs = filesys_info; fs; fs = fs->next) {
+               if (ignore(fs))
+                       fs->flags |= FLAG_DONE;
+       }
+               
+       while (not_done_yet) {
+               not_done_yet = 0;
+               pass_done = 1;
+
+               for (fs = filesys_info; fs; fs = fs->next) {
+                       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 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->device);
+                       fs->flags |= FLAG_DONE;
+
+                       if (serialize)
+                               break; /* Only do one filesystem at a time */
+               }
+               inst = wait_one();
+               if (inst) {
+                       status |= inst->exit_status;
+                       free_instance(inst);
+               }
+               if (pass_done) {
+                       status |= wait_all();
+                       if (verbose) 
+                               printf("----------------------------------\n");
+                       passno++;
+               } else
+                       not_done_yet++;
+       }
+       status |= wait_all();
+       return status;
+}
+
+static void usage(NOARGS)
+{
+       fprintf(stderr,
+               "Usage: fsck [-AV] [-t fstype] [fs-options] filesys\n");
+       exit(EXIT_USAGE);
+}
+
+static void PRS(int argc, char *argv[])
+{
+       int     i, j;
+       char    *arg;
+       char    options[128];
+       int     opt = 0;
+       int     opts_for_fsck = 0;
+       
+       num_devices = 0;
+       num_args = 0;
+       instance_list = 0;
+
+       progname = argv[0];
+
+       load_fs_info();
+
+       for (i=1; i < argc; i++) {
+               arg = argv[i];
+               if (!arg)
+                       continue;
+               if (arg[0] == '/') {
+                       if (num_devices >= MAX_DEVICES) {
+                               fprintf(stderr, "%s: too many devices\n",
+                                       progname);
+                               exit(1);
+                       }
+                       devices[num_devices++] = strdup(arg);
+                       continue;
+               }
+               if (arg[0] != '-') {
+                       if (num_args >= MAX_ARGS) {
+                               fprintf(stderr, "%s: too many arguments\n",
+                                       progname);
+                               exit(1);
+                       }
+                       args[num_args++] = strdup(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 'V':
+                               verbose++;
+                               break;
+                       case 'N':
+                               noexecute++;
+                               break;
+                       case 's':
+                               serialize++;
+                               break;
+                       case 't':
+                               if (arg[j+1]) {
+                                       fstype = strdup(arg+j+1);
+                                       goto next_arg;
+                               }
+                               if ((i+1) < argc) {
+                                       i++;
+                                       fstype = strdup(argv[i]);
+                                       goto next_arg;
+                               }
+                               usage();
+                               break;
+                       case '-':
+                               opts_for_fsck++;
+                               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(1);
+                       }
+                       args[num_args++] = strdup(options);
+                       opt = 0;
+               }
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       char *oldpath, newpath[PATH_MAX];
+       int status = 0;
+       int i;
+
+       PRS(argc, argv);
+
+       printf("Parallelizing fsck version %s (%s)\n", E2FSPROGS_VERSION,
+              E2FSPROGS_DATE);
+
+       /* Update our PATH to include /sbin, /etc/fs, and /etc. */
+       strcpy(newpath, "PATH=/sbin:/etc/fs:/etc:");
+       if ((oldpath = getenv("PATH")) != NULL)
+               strcat(newpath, oldpath);
+       putenv(newpath);
+    
+       /* If -A was specified ("check all"), do that! */
+       if (doall)
+               return check_all();
+
+       for (i = 0 ; i < num_devices; i++) {
+               fsck_device(devices[i]);
+               if (serialize) {
+                       struct fsck_instance *inst;
+
+                       inst = wait_one();
+                       if (!inst) {
+                               status |= inst->exit_status;
+                               free_instance(inst);
+                       }
+               }
+       }
+
+       status |= wait_all();
+       return status;
+}
diff --git a/misc/fsck.h b/misc/fsck.h
new file mode 100644 (file)
index 0000000..b79714b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * fsck.h
+ */
+
+#ifdef __STDC__
+#define NOARGS void
+#else
+#define NOARGS
+#define const
+#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
+
+/*
+ * Structure to allow exit codes to be stored
+ */
+struct fsck_instance {
+       int     pid;
+       int     flags;
+       int     exit_status;
+       char *  prog;
+       char *  device;
+       struct fsck_instance *next;
+};
+
+
+
diff --git a/misc/lsattr.1 b/misc/lsattr.1
new file mode 100644 (file)
index 0000000..51a0d5a
--- /dev/null
@@ -0,0 +1,40 @@
+.\" -*- nroff -*-
+.TH LSATTR 1 "March 1994" "Version 0.5"
+.SH NAME
+lsattr \- list file attributes on a Linux second extended file system
+.SH SYNOPSIS
+.B lsattr
+[
+.B \-Radv
+]
+[
+files...
+]
+.SH DESCRIPTION
+.B lsattr
+lists the files attributes on an second extended file system.
+.SH OPTIONS
+.TP
+.I -R
+Recursively list attributes of directories and their contents.
+.TP
+.I -a
+List all files in directories, including files that start with `.'.
+.TP
+.I -d
+List directories like other files, rather than listing their contents.
+.TP
+.I -v
+List the files version.
+.SH AUTHOR
+.B lsattr
+has been written by Remy Card <card@masi.ibp.fr>, the developer and maintainer
+of the ext2 fs.
+.SH BUGS
+There are none :-).
+.SH AVAILABILITY
+.B lsattr
+is available for anonymous ftp from ftp.ibp.fr (132.227.60.2) in
+/pub/linux/BETA/ext2fs.
+.SH SEE ALSO
+.BR chattr (1)
diff --git a/misc/lsattr.c b/misc/lsattr.c
new file mode 100644 (file)
index 0000000..ae337d6
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <linux/ext2_fs.h>
+
+#include "et/com_err.h"
+#include "e2p/e2p.h"
+
+#include "../version.h"
+
+const char * program_name = "lsattr";
+
+int all = 0;
+int d_opt = 0;
+int recursive = 0;
+int v_opt = 0;
+
+static void volatile usage (void)
+{
+       fprintf (stderr, "Usage: %s [-Radv] [files...]\n", program_name);
+       exit (1);
+}
+
+static void list_attributes (const char * name)
+{
+       unsigned long flags;
+       unsigned long version;
+
+       if (fgetflags (name, &flags) == -1)
+               com_err (program_name, errno, "While reading flags on %s",
+                        name);
+       else if (fgetversion (name, &version) == -1)
+               com_err (program_name, errno, "While reading version on %s",
+                        name);
+       else
+       {
+               if (v_opt)
+                       printf ("%5lu ", version);
+               print_flags (stdout, flags);
+               printf (" %s\n", name);
+       }
+}
+
+static int lsattr_dir_proc (const char *, struct dirent *, void *);
+
+static void lsattr_args (const char * name)
+{
+       struct stat st;
+
+       if (lstat (name, &st) == -1)
+               com_err (program_name, errno, "while stating %s", name);
+       else
+       {
+               if (S_ISDIR(st.st_mode) && !d_opt)
+                       iterate_on_dir (name, lsattr_dir_proc, (void *) NULL);
+               else
+                       list_attributes (name);
+       }
+}
+
+static int lsattr_dir_proc (const char * dir_name, struct dirent * de, void * private)
+{
+       char path [MAXPATHLEN];
+       struct stat st;
+
+       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, (void *) NULL);
+                               printf ("\n");
+                       }
+               }
+       }
+       return 0;
+}
+
+void main (int argc, char ** argv)
+{
+       char c;
+       int i;
+
+       fprintf (stderr, "lsattr %s, %s for EXT2 FS %s, %s\n",
+                E2FSPROGS_VERSION, E2FSPROGS_DATE,
+                EXT2FS_VERSION, EXT2FS_DATE);
+       if (argc && *argv)
+               program_name = *argv;
+       while ((c = getopt (argc, argv, "Radlv")) != EOF)
+               switch (c)
+               {
+                       case 'R':
+                               recursive = 1;
+                               break;
+                       case 'a':
+                               all = 1;
+                               break;
+                       case 'd':
+                               d_opt = 1;
+                               break;
+                       case 'v':
+                               v_opt = 1;
+                               break;
+                       default:
+                               usage ();
+               }
+
+       if (optind > argc - 1)
+               lsattr_args (".");
+       else
+               for (i = optind; i < argc; i++)
+                       lsattr_args (argv[i]);
+}
diff --git a/misc/mke2fs.8 b/misc/mke2fs.8
new file mode 100644 (file)
index 0000000..5b1e5bc
--- /dev/null
@@ -0,0 +1,104 @@
+.\" -*- nroff -*-
+.TH MKE2FS 8 "March 1994" "Version 0.5"
+.SH NAME
+mke2fs \- create a Linux second extended file system
+.SH SYNOPSIS
+.B mke2fs
+[
+.B \-c
+| 
+.\" .B \-t
+.\" test
+.\" |
+.B \-l
+filename
+]
+[
+.B \-b
+block-size
+]
+[
+.B \-f
+fragment-size
+]
+[
+.B \-i
+bytes-per-inode
+]
+[
+.B \-m
+reserved-blocks-percentage
+]
+[
+.B \-v
+]
+device
+[
+blocks-count
+]
+.SH DESCRIPTION
+.B mke2fs
+is used to create a Linux second extended file system on a device (usually
+a disk partition).
+.br
+.I device
+is the special file corresponding to the device (e.g /dev/hdXX).
+.br
+.I blocks-count
+is the number of blocks on the device.  If omitted,
+.B mke2fs
+automagically figures the file system size.
+.SH OPTIONS
+.TP
+.I -b block-size
+Specify the size of blocks in bytes.
+.TP
+.I -c
+Check the device for bad blocks before creating the file system, using a
+fast read-only test.
+.TP
+.I -f fragment-size
+Specify the size of fragments in bytes.
+.TP
+.I -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.  This value defaults to 4096 bytes.
+.I bytes-per-inode
+must be at least 1024.
+.TP
+.I -l filename
+Read the bad blocks list from
+.I filename
+\.
+.TP
+.I -m reserved-blocks-percentage
+Specify the percentage of reserved blocks for the super-user.  This value
+defaults to 5%.
+.\" .TP
+.\" .I -t test
+.\" Check the device for bad blocks before creating the file system
+.\" using the specified test.
+.TP
+.I -v
+Verbose execution.
+.SH AUTHOR
+This version of
+.B mke2fs
+has been written by Theodore T'so <tytso@mit.edu>.
+.SH BUGS
+.B mke2fs
+accepts the -f option but currently ignores it because the second
+extended file system does not support fragments yet.
+.br
+There may be some other ones.  Please, report them to the author.
+.SH AVAILABILITY
+.B mke2fs
+is available for anonymous ftp from ftp.ibp.fr (132.227.60.2) in
+/pub/linux/BETA/ext2fs.
+.SH SEE ALSO
+.BR dumpe2fs (8),
+.BR e2fsck (8),
+.BR tune2fs (8)
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
new file mode 100644 (file)
index 0000000..9d36ee9
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * mke2fs.c - Make a ext2fs filesystem.
+ * 
+ * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+/* 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 :-). 
+ */
+
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <termios.h>
+#include <time.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <mntent.h>
+#include <malloc.h>
+#include <sys/ioctl.h>
+#include <linux/ext2_fs.h>
+#include <linux/fs.h>
+
+#include "et/com_err.h"
+#include "ext2fs/ext2fs.h"
+#include "../version.h"
+
+#define STRIDE_LENGTH 8
+
+extern int isatty(int);
+
+const char * program_name = "mke2fs";
+const char * device_name = NULL;
+
+/* Command line options */
+int    cflag = 0;
+int    verbose = 0;
+int    quiet = 0;
+char   *bad_blocks_filename = 0;
+
+struct ext2_super_block param;
+
+static void usage(NOARGS)
+{
+       fprintf(stderr,
+               "Usage: %s [-c|-t|-l filename] [-b block-size] "
+               "[-f fragment-size]\n\t[-i bytes-per-inode] "
+               "[-m reserved-blocks-percentage] [-v]\n"
+               "\tdevice [blocks-count]\n",
+               program_name);
+       exit(1);
+}
+
+static int log2(int arg)
+{
+       int     l = 0;
+
+       arg >>= 1;
+       while (arg) {
+               l++;
+               arg >>= 1;
+       }
+       return l;
+}
+
+static long valid_offset (int fd, int offset)
+{
+       char ch;
+
+       if (lseek (fd, offset, 0) < 0)
+               return 0;
+       if (read (fd, &ch, 1) < 1)
+               return 0;
+       return 1;
+}
+
+static int count_blocks (int fd)
+{
+       int high, low;
+
+       low = 0;
+       for (high = 1; valid_offset (fd, high); high *= 2)
+               low = high;
+       while (low < high - 1)
+       {
+               const int mid = (low + high) / 2;
+
+               if (valid_offset (fd, mid))
+                       low = mid;
+               else
+                       high = mid;
+       }
+       valid_offset (fd, 0);
+       return (low + 1) / 1024;
+}
+
+static int get_size(const char  *file)
+{
+       int     fd;
+       int     size;
+
+       fd = open(file, O_RDWR);
+       if (fd < 0) {
+               com_err("open", errno, "while trying to determine size of %s",
+                       file);
+               exit(1);
+       }
+       if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+               close(fd);
+               return size / (EXT2_BLOCK_SIZE(&param) / 512);
+       }
+               
+       size = count_blocks(fd);
+       close(fd);
+       return size;
+}
+
+static void check_mount(NOARGS)
+{
+       FILE * f;
+       struct mntent * mnt;
+
+       if ((f = setmntent (MOUNTED, "r")) == NULL)
+               return;
+       while ((mnt = getmntent (f)) != NULL)
+               if (strcmp (device_name, mnt->mnt_fsname) == 0)
+                       break;
+       endmntent (f);
+       if (!mnt)
+               return;
+
+       fprintf(stderr, "%s is mounted; will not make a filesystem here!\n",
+               device_name);
+       exit(1);
+}
+
+/*
+ * Helper function for read_bb_file and test_disk
+ */
+static void invalid_block(ext2_filsys fs, blk_t blk)
+{
+       printf("Bad block %lu 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,
+                       "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 %s%s %ld", quiet ? "" : "-s ",
+               fs->device_name,
+               fs->super->s_blocks_count);
+       if (verbose)
+               printf("Running command: %s\n", buf);
+       f = popen(buf, "r");
+       if (!f) {
+               com_err("popen", errno,
+                       "while trying run '%s'", buf);
+               exit(1);
+       }
+       retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
+       fclose (f);
+       if (retval) {
+               com_err("ext2fs_read_bb_FILE", retval,
+                       "while processing list of bad blocks from program");
+               exit(1);
+       }
+}
+
+static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list)
+{
+       int                     i;
+       int                     must_be_good;
+       blk_t                   blk;
+       badblocks_iterate       bb_iter;
+       errcode_t               retval;
+
+       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 (badblocks_list_test(bb_list, i)) {
+                       fprintf(stderr, "Block %d in primary superblock/group "
+                               "descriptor area bad.\n", i);
+                       fprintf(stderr, "Blocks %ld through %d must be good "
+                               "in order to build a filesystem.\n",
+                               fs->super->s_first_data_block, must_be_good);
+                       fprintf(stderr, "Aborting....\n");
+                       exit(1);
+               }
+       }
+       
+       /*
+        * Mark all the bad blocks as used...
+        */
+       retval = badblocks_list_iterate_begin(bb_list, &bb_iter);
+       if (retval) {
+               com_err("badblocks_list_iterate_begin", retval,
+                       "while marking bad blocks as used");
+               exit(1);
+       }
+       while (badblocks_list_iterate(bb_iter, &blk)) 
+               ext2fs_mark_block_bitmap(fs, fs->block_map, blk);
+       badblocks_list_iterate_end(bb_iter);
+}
+
+static void new_table_block(ext2_filsys fs, blk_t first_block,
+                           const char *name, int num, const char *buf,
+                           blk_t *new_block)
+{
+       errcode_t       retval;
+       blk_t           blk;
+       int             i;
+       int             count;
+       
+       retval = ext2fs_get_free_blocks(fs, first_block,
+                       first_block + fs->super->s_blocks_per_group,
+                                       num, fs->block_map, new_block);
+       if (retval) {
+               printf("Could not allocate %d block(s) for %s: %s\n",
+                      num, name, error_message(retval));
+               ext2fs_unmark_valid(fs);
+               return;
+       }
+       blk = *new_block;
+       for (i=0; i < num; i += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
+               if (num-i > STRIDE_LENGTH)
+                       count = STRIDE_LENGTH;
+               else
+                       count = num - i;
+               retval = io_channel_write_blk(fs->io, blk, count, buf);
+               if (retval)
+                       printf("Warning: could not write %d blocks starting "
+                              "at %ld for %s: %s\n",
+                              count, blk, name, error_message(retval));
+       }
+       blk = *new_block;
+       for (i = 0; i < num; i++, blk++)
+               ext2fs_mark_block_bitmap(fs, fs->block_map, blk);
+}      
+
+static void alloc_tables(ext2_filsys fs)
+{
+       blk_t   group_blk;
+       int     i;
+       char    *buf;
+       int     numblocks;
+
+       buf = malloc(fs->blocksize * STRIDE_LENGTH);
+       if (!buf) {
+               com_err("malloc", ENOMEM, "while allocating zeroizing buffer");
+               exit(1);
+       }
+       memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
+       
+       group_blk = fs->super->s_first_data_block;
+       if (!quiet)
+               printf("Writing inode tables: ");
+       for (i = 0; i < fs->group_desc_count; i++) {
+               if (!quiet)
+                       printf("%4d/%4ld", i, fs->group_desc_count);
+               new_table_block(fs, group_blk, "block bitmap", 1, buf,
+                               &fs->group_desc[i].bg_block_bitmap);
+               new_table_block(fs, group_blk, "inode bitmap", 1, buf,
+                               &fs->group_desc[i].bg_inode_bitmap);
+               new_table_block(fs, group_blk, "inode table",
+                               fs->inode_blocks_per_group, buf,
+                               &fs->group_desc[i].bg_inode_table);
+               
+               if (i == fs->group_desc_count-1) {
+                       numblocks = (fs->super->s_blocks_count -
+                                    fs->super->s_first_data_block) %
+                                            fs->super->s_blocks_per_group;
+                       if (!numblocks)
+                               numblocks = fs->super->s_blocks_per_group;
+               } else
+                       numblocks = fs->super->s_blocks_per_group;
+               numblocks -= 3 + fs->desc_blocks + fs->inode_blocks_per_group;
+               
+               fs->group_desc[i].bg_free_blocks_count = numblocks;
+               fs->group_desc[i].bg_free_inodes_count =
+                       fs->super->s_inodes_per_group;
+               fs->group_desc[i].bg_used_dirs_count = 0;
+               group_blk += fs->super->s_blocks_per_group;
+               if (!quiet) 
+                       printf("\b\b\b\b\b\b\b\b\b");
+       }
+       if (!quiet)
+               printf("done     \n");
+}
+
+static void create_root_dir(ext2_filsys fs)
+{
+       errcode_t       retval;
+
+       retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
+       if (retval) {
+               com_err("ext2fs_mkdir", retval, "while creating root dir");
+               exit(1);
+       }
+}
+
+static void create_lost_and_found(ext2_filsys fs)
+{
+       errcode_t               retval;
+       ino_t                   ino;
+       const char              *name = "lost+found";
+       int                     i;
+
+       retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name);
+       if (retval) {
+               com_err("ext2fs_mkdir", retval, "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, "while looking up /lost+found");
+               exit(1);
+       }
+       
+       for (i=1; i < EXT2_NDIR_BLOCKS; i++) {
+               retval = ext2fs_expand_dir(fs, ino);
+               if (retval) {
+                       com_err("ext2fs_expand_dir", retval,
+                               "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_bitmap(fs, fs->inode_map, EXT2_BAD_INO);
+       fs->group_desc[0].bg_free_inodes_count--;
+       fs->super->s_free_inodes_count--;
+       retval = ext2fs_update_bb_inode(fs, bb_list);
+       if (retval) {
+               com_err("ext2fs_update_bb_inode", retval,
+                       "while setting bad block inode");
+               exit(1);
+       }
+
+}
+
+static void reserve_inodes(ext2_filsys fs)
+{
+       ino_t   i;
+       int     group;
+
+       for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INO; i++) {
+               ext2fs_mark_inode_bitmap (fs, fs->inode_map, i);
+               group = ext2fs_group_of_ino(fs, i);
+               fs->group_desc[group].bg_free_inodes_count--;
+               fs->super->s_free_inodes_count--;
+       }
+       ext2fs_mark_ib_dirty(fs);
+}
+
+static void show_stats(ext2_filsys fs)
+{
+       struct ext2_super_block *s = fs->super;
+       blk_t                   group_block;
+       int                     i, col_left;
+       
+       if (param.s_blocks_count != s->s_blocks_count)
+               printf("warning: %ld blocks unused.\n\n",
+                      param.s_blocks_count - s->s_blocks_count);
+       
+       printf("%lu inodes, %lu blocks\n", s->s_inodes_count,
+              s->s_blocks_count);
+       printf("%lu blocks (%2.2f%%) reserved for the super user\n",
+               s->s_r_blocks_count,
+              100.0 * s->s_r_blocks_count / s->s_blocks_count);
+       printf("First data block=%lu\n", s->s_first_data_block);
+       printf("Block size=%u (log=%lu)\n", fs->blocksize,
+               s->s_log_block_size);
+       printf("Fragment size=%u (log=%lu)\n", fs->fragsize,
+               s->s_log_frag_size);
+       printf("%lu block group%s\n", fs->group_desc_count,
+               (fs->group_desc_count > 1) ? "s" : "");
+       printf("%lu blocks per group, %lu fragments per group\n",
+              s->s_blocks_per_group, s->s_frags_per_group);
+       printf("%lu inodes per group\n", s->s_inodes_per_group);
+
+       if (fs->group_desc_count == 1) {
+               printf("\n");
+               return;
+       }
+       
+       printf("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 (!col_left--) {
+                       printf("\n\t");
+                       col_left = 8;
+               }
+               printf("%lu", group_block);
+               if (i != fs->group_desc_count - 1)
+                       printf(", ");
+       }
+       printf("\n\n");
+}
+
+static void PRS(int argc, char *argv[])
+{
+       char    c;
+       int     size;
+       char    * tmp;
+       char *oldpath, newpath[PATH_MAX];
+       int     inode_ratio = 4096;
+       int     reserved_ratio = 5;
+
+       /* Update our PATH to include /sbin  */
+       strcpy(newpath, "PATH=/sbin:");
+       if ((oldpath = getenv("PATH")) != NULL)
+               strcat(newpath, oldpath);
+       putenv(newpath);
+
+       setbuf(stdout, NULL);
+       setbuf(stderr, NULL);
+       initialize_ext2_error_table();
+       memset(&param, 0, sizeof(struct ext2_super_block));
+       
+       fprintf (stderr, "mke2fs %s, %s for EXT2 FS %s, %s\n",
+                E2FSPROGS_VERSION, E2FSPROGS_DATE,
+                EXT2FS_VERSION, EXT2FS_DATE);
+       if (argc && *argv)
+               program_name = *argv;
+       while ((c = getopt (argc, argv, "b:cf:g:i:l:m:qtv")) != EOF)
+               switch (c) {
+               case 'b':
+                       size = strtoul(optarg, &tmp, 0);
+                       if (size < 1024 || size > 4096 || *tmp) {
+                               com_err(program_name, 0, "bad block size - %s",
+                                       optarg);
+                               exit(1);
+                       }
+                       param.s_log_block_size =
+                               log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
+                       break;
+               case 'c':
+               case 't':       /* Check for bad blocks */
+                       cflag = 1;
+                       break;
+               case 'f':
+                       size = strtoul(optarg, &tmp, 0);
+                       if (size < 1024 || size > 4096 || *tmp) {
+                               com_err(program_name, 0, "bad fragment size - %s",
+                                       optarg);
+                               exit(1);
+                       }
+                       param.s_log_frag_size =
+                               log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
+                       printf("Warning: fragments not supported.  "
+                              "Ignoring -f option\n");
+                       break;
+               case 'g':
+                       param.s_blocks_per_group = strtoul(optarg, &tmp, 0);
+                       if (param.s_blocks_per_group < 256 ||
+                           param.s_blocks_per_group > 8192 || *tmp) {
+                               com_err(program_name, 0,
+                                       "bad blocks per group count - %s",
+                                       optarg);
+                               exit(1);
+                       }
+                       break;
+               case 'i':
+                       inode_ratio = strtoul(optarg, &tmp, 0);
+                       if (inode_ratio < 1024 || inode_ratio > 256 * 1024 ||
+                           *tmp) {
+                               com_err(program_name, 0, "bad inode ratio - %s",
+                                       optarg);
+                               exit(1);
+                       }
+                       break;
+               case 'l':
+                       bad_blocks_filename = strdup(optarg);
+                       break;
+               case 'm':
+                       reserved_ratio = strtoul(optarg, &tmp, 0);
+                       if (reserved_ratio > 50 || *tmp) {
+                               com_err(program_name, 0,
+                                       "bad reserved blocks percent - %s",
+                                       optarg);
+                               exit(1);
+                       }
+                       break;
+               case 'v':
+                       verbose = 1;
+                       break;
+               case 'q':
+                       quiet = 1;
+                       break;
+               default:
+                       usage();
+               }
+       if (optind == argc)
+               usage();
+       device_name = argv[optind];
+       optind++;
+       if (optind < argc) {
+               param.s_blocks_count = strtoul(argv[optind++], &tmp, 0);
+               if (*tmp) {
+                       com_err(program_name, 0, "bad blocks count - %s",
+                               argv[optind - 1]);
+                       exit(1);
+               }
+       }
+       if (optind < argc)
+               usage();
+       param.s_log_frag_size = param.s_log_block_size;
+
+       if (!param.s_blocks_count)
+               param.s_blocks_count = get_size(device_name);
+
+       /*
+        * Calculate number of inodes based on the inode ratio
+        */
+       param.s_inodes_count =
+               (param.s_blocks_count * EXT2_BLOCK_SIZE(&param)) / inode_ratio;
+
+       /*
+        * Calculate number of blocks to reserve
+        */
+       param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100;
+}
+                                       
+int main (int argc, char *argv[])
+{
+       errcode_t       retval = 0;
+       ext2_filsys     fs;
+       badblocks_list  bb_list = 0;
+       
+       PRS(argc, argv);
+
+       check_mount();
+
+       /*
+        * Initialize the superblock....
+        */
+       retval = ext2fs_initialize(device_name, 0, &param,
+                                  unix_io_manager, &fs);
+       if (retval) {
+               com_err(device_name, retval, "while setting up superblock");
+               exit(1);
+       }
+
+       if (!quiet)
+               show_stats(fs);
+
+       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);
+       alloc_tables(fs);
+       create_root_dir(fs);
+       create_lost_and_found(fs);
+       reserve_inodes(fs);
+       create_bad_block_inode(fs, bb_list);
+       
+       if (!quiet)
+               printf("Writing superblocks and "
+                      "filesystem accounting information: ");
+       ext2fs_close(fs);
+       if (!quiet)
+               printf("done\n");
+       return 0;
+}
diff --git a/misc/mklost+found.8 b/misc/mklost+found.8
new file mode 100644 (file)
index 0000000..b566318
--- /dev/null
@@ -0,0 +1,30 @@
+.\" -*- nroff -*-
+.TH MKLOST+FOUND 8 "March 1994" "Version 0.5"
+.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 lost+found directory in the current working directory
+on a Linux second extended file system.
+.br
+.B mklost+found
+pre-allocates disk blocks to the directory to make it usable by
+.B e2fsck
+.SH OPTIONS
+There are none.
+.SH AUTHOR
+.B mklost+found
+has been written by Remy Card <card@masi.ibp.fr>, the developer and maintainer
+of the ext2 fs.
+.SH BUGS
+There are none :-)
+.SH AVAILABILITY
+.B mklost+found
+is available for anonymous ftp from ftp.ibp.fr (132.227.60.2) in
+/pub/linux/BETA/ext2fs.
+.SH SEE ALSO
+.BR e2fsck (8),
+.BR mke2fs (8)
diff --git a/misc/mklost+found.c b/misc/mklost+found.c
new file mode 100644 (file)
index 0000000..299e47c
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <linux/ext2_fs.h>
+
+#include "../version.h"
+
+#define LPF "lost+found"
+
+void main (int argc, char ** argv)
+{
+       char name [EXT2_NAME_LEN];
+       char path [MAXPATHLEN];
+       struct stat st;
+       int i, j;
+       int d;
+
+       fprintf (stderr, "mklost+found %s, %s for EXT2 FS %s, %s\n",
+                E2FSPROGS_VERSION, E2FSPROGS_DATE,
+                EXT2FS_VERSION, EXT2FS_DATE);
+       if (argc != 1) {
+               fprintf (stderr, "Usage: mklost+found\n");
+               exit(1);
+       }
+       if (mkdir (LPF, 0755) == -1) {
+               perror ("mkdir");
+               exit(1);
+       }
+       
+       i = 0;
+       memset (name, 'x', 252);
+       do {
+               sprintf (name + 252, "%02d", 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 + 252, "%02d", j);
+               strcpy (path, LPF);
+               strcat (path, "/");
+               strcat (path, name);
+               if (unlink (path) == -1) {
+                       perror ("unlink");
+                       exit (1);
+               }
+       }
+       exit (0);
+}
diff --git a/misc/tune2fs.8 b/misc/tune2fs.8
new file mode 100644 (file)
index 0000000..3d99704
--- /dev/null
@@ -0,0 +1,71 @@
+.\" Revision 1.0 93/06/3 23:00  chk
+.\" Initial revision
+.\"
+.\"
+.TH TUNE2FS 8 "March 1994" "Version 0.5"
+
+.SH NAME
+tune2fs \- adjust tunable filesystem parameters on second extended filesystems
+.SH SYNOPSIS
+.B tune2fs
+[
+.B options
+]
+device
+.SH DESCRIPTION
+.BI tune2fs
+adjusts tunable filesystem parameters on a Linux second extended filesystem.
+.PP
+.B Never use tune2fs on a read/write mounted filesystem to change parameters!
+.PP
+.SH OPTIONS
+.TP
+.I -c max-mount-counts
+adjust the maximal mounts count between two filesystem checks.
+.TP
+.I -e errors-behavior
+change the behavior of the kernel code when errors are detected.
+.I errors-behavior
+can be one of the followings:
+.br
+\      continue\       \       Continue normal execution.
+.br
+\      remount-ro\     Remount the filesystem read-only.
+.br
+\      panic\  \       Causes a kernel panic.
+.TP
+.I -i interval-between-checks[d|m]
+adjust the maximal time between two filesystem checks. 
+No postfix or `d' result in days, and 'm' in months.
+A value of zero will disable the timedependent checking.
+.TP
+.I -l
+list the contents of the filesystem superblock.
+.TP
+.I -m reserved-blocks-percentage
+adjust the reserved blocks percentage on the given device.
+.PP
+.SH BUGS
+We didn't find any bugs yet. Perhaps there are bugs but it's unlikely.
+.PP
+.SH WARNING
+.B Use this utility on your own risk. You're modifying filesystems.
+.SH AUTHOR
+.B tune2fs 
+has been written by Remy Card <card@masi.ibp.fr>, the developer and maintainer
+of the ext2 fs.
+.br
+.B tune2fs
+uses the ext2fs library written by Theodore T'so <tytso@mit.edu>.
+.br
+This manual page was written by Christian Kuhtz <chk@data-hh.Hanse.DE>.
+.br
+Timedependent checking was added by Uwe Ohse <uwe@tirka.gun.de>.
+.SH AVAILABILITY
+.B tune2fs
+is available for anonymous ftp from ftp.ibp.fr (132.227.60.2) in
+/pub/linux/BETA/ext2fs.
+.SH SEE ALSO
+.BR dumpe2fs (8),
+.BR e2fsck (8),
+.BR mke2fs (8)
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
new file mode 100644 (file)
index 0000000..2f0d860
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * tune2fs.c           - Change the file system parameters on
+ *                       an unmounted second extended 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)
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+/*
+ * 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)
+ */
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/ext2_fs.h>
+
+#include "ext2fs/ext2fs.h"
+#include "et/com_err.h"
+#include "e2p/e2p.h"
+
+#include "../version.h"
+
+const char * program_name = "tune2fs";
+char * device_name = NULL;
+int c_flag = 0;
+int e_flag = 0;
+int i_flag = 0;
+int l_flag = 0;
+int m_flag = 0;
+int max_mount_count;
+unsigned long interval;
+unsigned long reserved_ratio = 0;
+unsigned short errors;
+
+static volatile void usage (void)
+{
+       fprintf (stderr, "Usage: %s [-c max-mounts-count] [-e errors-behavior] "
+                "[-i interval[d|m]]\n"
+                "\t[-l] [-m reserved-blocks-percent] device\n", program_name);
+       exit (1);
+}
+
+void main (int argc, char ** argv)
+{
+       char c;
+       char * tmp;
+       errcode_t retval;
+       ext2_filsys fs;
+
+       fprintf (stderr, "tune2fs %s, %s for EXT2 FS %s, %s\n",
+                E2FSPROGS_VERSION, E2FSPROGS_DATE,
+                EXT2FS_VERSION, EXT2FS_DATE);
+       if (argc && *argv)
+               program_name = *argv;
+       initialize_ext2_error_table();
+       while ((c = getopt (argc, argv, "c:e:i:lm:")) != EOF)
+               switch (c)
+               {
+                       case 'c':
+                               max_mount_count = strtoul (optarg, &tmp, 0);
+                               if (*tmp || max_mount_count > 16000)
+                               {
+                                       com_err (program_name, 0,
+                                                "bad mounts count - %s",
+                                                optarg);
+                                       usage ();
+                               }
+                               c_flag = 1;
+                               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;
+                               break;
+                       case 'i':
+                               interval = strtoul (optarg, &tmp, 0);
+                               switch (*tmp)
+                               {
+                                       case '\0':
+                                       case 'd':
+                                       case 'D': /* days */
+                                               interval *= 86400;
+                                               if (*tmp != '\0')
+                                                       tmp++;
+                                               break;
+                                       case 'm':
+                                       case 'M': /* months! */
+                                               interval *= 86400 * 30;
+                                               tmp++;
+                                               break;
+                               }
+                               if (*tmp || interval > (365 * 86400))
+                               {
+                                       com_err (program_name, 0,
+                                                "bad interval - %s", optarg);
+                                       usage ();
+                               }
+                               i_flag = 1;
+                               break;
+                       case 'l':
+                               l_flag = 1;
+                               break;
+                       case 'm':
+                               reserved_ratio = strtoul (optarg, &tmp, 0);
+                               if (*tmp || reserved_ratio > 50)
+                               {
+                                       com_err (program_name, 0,
+                                                "bad reserved block ratio - %s",
+                                                optarg);
+                                       usage ();
+                               }
+                               m_flag = 1;
+                               break;
+                       default:
+                               usage ();
+               }
+       if (optind < argc - 1 || optind == argc)
+               usage ();
+       if (!c_flag && !e_flag && !i_flag && !m_flag && !l_flag)
+               usage ();
+       device_name = argv[optind];
+       retval = ext2fs_open (device_name,
+                             (c_flag || e_flag || i_flag || m_flag) ? EXT2_FLAG_RW : 0,
+                             0, 0, unix_io_manager, &fs);
+        if (retval)
+       {
+               com_err (program_name, retval, "while trying to open %s",
+                        device_name);
+               printf("Couldn't find valid filesystem superblock.\n");
+               exit(1);
+       }
+
+       if (c_flag)
+       {
+               fs->super->s_max_mnt_count = max_mount_count;
+               ext2fs_mark_super_dirty(fs);
+               printf ("Setting maximal mount count to %d\n", max_mount_count);
+       }
+       if (e_flag)
+       {
+               fs->super->s_errors = errors;
+               ext2fs_mark_super_dirty(fs);
+               printf ("Setting error behavior to %d\n", errors);
+       }
+       if (i_flag)
+       {
+               fs->super->s_checkinterval = interval;
+               ext2fs_mark_super_dirty(fs);
+               printf ("Setting interval between check %lu seconds\n", interval);
+       }
+       if (m_flag)
+       {
+               fs->super->s_r_blocks_count = (fs->super->s_blocks_count / 100)
+                       * reserved_ratio;
+               ext2fs_mark_super_dirty(fs);
+               printf ("Setting reserved blocks percentage to %lu (%lu blocks)\n",
+                       reserved_ratio, fs->super->s_r_blocks_count);
+       }
+       if (l_flag)
+               list_super (fs->super);
+       ext2fs_close (fs);
+       exit (0);
+}
diff --git a/version.h b/version.h
new file mode 100644 (file)
index 0000000..08bd0c3
--- /dev/null
+++ b/version.h
@@ -0,0 +1,10 @@
+/*
+ * version.h --- controls the version number printed by the e2fs
+ * programs.
+ *
+ * Copyright 1994, Theodore Ts'o.  This file may be redistributed
+ * under the GNU Public License.
+ */
+
+#define E2FSPROGS_VERSION "0.5"
+#define E2FSPROGS_DATE "28-Mar-94"