Many files:
  Checkin of e2fsprogs 0.5b

diff --git a/INSTALL b/INSTALL
new file mode 100644
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
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
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
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
index 0000000..0788c38
--- /dev/null
+++ b/debugfs/.depend
@@ -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
index 0000000..65b32ae
--- /dev/null
+++ b/debugfs/Makefile
@@ -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
index 0000000..cd7faf1
--- /dev/null
+++ b/debugfs/debug_cmds.ct
@@ -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
index 0000000..3d03e6b
--- /dev/null
+++ b/debugfs/debugfs.8
@@ -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
index 0000000..b92746a
--- /dev/null
+++ b/debugfs/debugfs.c
@@ -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
index 0000000..f7f5f08
--- /dev/null
+++ b/debugfs/debugfs.h
@@ -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
index 0000000..848c76a
--- /dev/null
+++ b/debugfs/icheck.c
@@ -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
index 0000000..062e7c5
--- /dev/null
+++ b/debugfs/ncheck.c
@@ -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
index 0000000..24957fb
--- /dev/null
+++ b/debugfs/util.c
@@ -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
index 0000000..e48c1af
--- /dev/null
+++ b/e2fsck/.depend
@@ -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
index 0000000..fa135b6
--- /dev/null
+++ b/e2fsck/CHANGES
@@ -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
index 0000000..c0c64c6
--- /dev/null
+++ b/e2fsck/Makefile
@@ -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
index 0000000..6dff23d
--- /dev/null
+++ b/e2fsck/badblocks.c
@@ -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
index 0000000..101ccee
--- /dev/null
+++ b/e2fsck/dirinfo.c
@@ -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
index 0000000..d79903c
--- /dev/null
+++ b/e2fsck/e2fsck.8
@@ -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
index 0000000..37d202b
--- /dev/null
+++ b/e2fsck/e2fsck.c
@@ -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
index 0000000..a25f461
--- /dev/null
+++ b/e2fsck/e2fsck.h
@@ -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
index 0000000..96aedfb
--- /dev/null
+++ b/e2fsck/ehandler.c
@@ -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
index 0000000..eba4e85
--- /dev/null
+++ b/e2fsck/flushb.c
@@ -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
index 0000000..bd111fd
--- /dev/null
+++ b/e2fsck/images/README
@@ -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
index 0000000..c7af6c5
--- /dev/null
+++ b/e2fsck/images/baddir.img.gz
Binary files differ
diff --git a/e2fsck/images/badinode.img.gz b/e2fsck/images/badinode.img.gz
new file mode 100644
index 0000000..7d10bc1
--- /dev/null
+++ b/e2fsck/images/badinode.img.gz
Binary files differ
diff --git a/e2fsck/images/badlkcnt.img.gz b/e2fsck/images/badlkcnt.img.gz
new file mode 100644
index 0000000..96509f5
--- /dev/null
+++ b/e2fsck/images/badlkcnt.img.gz
Binary files differ
diff --git a/e2fsck/images/badroot.img.gz b/e2fsck/images/badroot.img.gz
new file mode 100644
index 0000000..5724105
--- /dev/null
+++ b/e2fsck/images/badroot.img.gz
Binary files differ
diff --git a/e2fsck/images/badtable.img.gz b/e2fsck/images/badtable.img.gz
new file mode 100644
index 0000000..72934ce
--- /dev/null
+++ b/e2fsck/images/badtable.img.gz
Binary files differ
diff --git a/e2fsck/images/bbfile.img.gz b/e2fsck/images/bbfile.img.gz
new file mode 100644
index 0000000..155363a
--- /dev/null
+++ b/e2fsck/images/bbfile.img.gz
Binary files differ
diff --git a/e2fsck/images/bitmaps.img.gz b/e2fsck/images/bitmaps.img.gz
new file mode 100644
index 0000000..7eff4fc
--- /dev/null
+++ b/e2fsck/images/bitmaps.img.gz
Binary files differ
diff --git a/e2fsck/images/dirlink.img.gz b/e2fsck/images/dirlink.img.gz
new file mode 100644
index 0000000..7e1694a
--- /dev/null
+++ b/e2fsck/images/dirlink.img.gz
Binary files differ
diff --git a/e2fsck/images/dup.img.gz b/e2fsck/images/dup.img.gz
new file mode 100644
index 0000000..f901f19
--- /dev/null
+++ b/e2fsck/images/dup.img.gz
Binary files differ
diff --git a/e2fsck/images/dup2.img.gz b/e2fsck/images/dup2.img.gz
new file mode 100644
index 0000000..f5fcd37
--- /dev/null
+++ b/e2fsck/images/dup2.img.gz
Binary files differ
diff --git a/e2fsck/images/end-bitmap.img.gz b/e2fsck/images/end-bitmap.img.gz
new file mode 100644
index 0000000..b83478f
--- /dev/null
+++ b/e2fsck/images/end-bitmap.img.gz
Binary files differ
diff --git a/e2fsck/images/expand.img.gz b/e2fsck/images/expand.img.gz
new file mode 100644
index 0000000..0ea6729
--- /dev/null
+++ b/e2fsck/images/expand.img.gz
Binary files differ
diff --git a/e2fsck/images/lpf.img.gz b/e2fsck/images/lpf.img.gz
new file mode 100644
index 0000000..527c09b
--- /dev/null
+++ b/e2fsck/images/lpf.img.gz
Binary files differ
diff --git a/e2fsck/images/mke2fs2b.img.gz b/e2fsck/images/mke2fs2b.img.gz
new file mode 100644
index 0000000..9716a13
--- /dev/null
+++ b/e2fsck/images/mke2fs2b.img.gz
Binary files differ
diff --git a/e2fsck/images/noroot.img.gz b/e2fsck/images/noroot.img.gz
new file mode 100644
index 0000000..3e597f3
--- /dev/null
+++ b/e2fsck/images/noroot.img.gz
Binary files differ
diff --git a/e2fsck/images/test_script b/e2fsck/images/test_script
new file mode 100644
index 0000000..c0842ef
--- /dev/null
+++ b/e2fsck/images/test_script
@@ -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
index 0000000..c583fe5
--- /dev/null
+++ b/e2fsck/images/test_script.log
@@ -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
index 0000000..3e46718
--- /dev/null
+++ b/e2fsck/malloc.h
@@ -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
index 0000000..7e96b8a
--- /dev/null
+++ b/e2fsck/mtrace.awk
@@ -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
index 0000000..8553a64
--- /dev/null
+++ b/e2fsck/mtrace.c
@@ -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
index 0000000..2f23b9d
--- /dev/null
+++ b/e2fsck/pass1.c
@@ -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
index 0000000..dd657bf
--- /dev/null
+++ b/e2fsck/pass1b.c
@@ -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
index 0000000..327cf16
--- /dev/null
+++ b/e2fsck/pass2.c
@@ -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
index 0000000..b34acd2
--- /dev/null
+++ b/e2fsck/pass3.c
@@ -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
index 0000000..290e1b9
--- /dev/null
+++ b/e2fsck/pass4.c
@@ -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
index 0000000..cd0cf5b
--- /dev/null
+++ b/e2fsck/pass5.c
@@ -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
index 0000000..c9e6396
--- /dev/null
+++ b/e2fsck/util.c
@@ -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
index 0000000..12950ef
--- /dev/null
+++ b/lib/e2p/.depend
@@ -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
index 0000000..e890bb5
--- /dev/null
+++ b/lib/e2p/Makefile
@@ -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
index 0000000..d459e87
--- /dev/null
+++ b/lib/e2p/e2p.h
@@ -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
index 0000000..95b0bdc
--- /dev/null
+++ b/lib/e2p/fgetflags.c
@@ -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
index 0000000..73429f2
--- /dev/null
+++ b/lib/e2p/fgetversion.c
@@ -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
index 0000000..180d48f
--- /dev/null
+++ b/lib/e2p/fsetflags.c
@@ -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
index 0000000..1bb8acc
--- /dev/null
+++ b/lib/e2p/fsetversion.c
@@ -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
index 0000000..4e53749
--- /dev/null
+++ b/lib/e2p/getflags.c
@@ -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
index 0000000..04dc0f7
--- /dev/null
+++ b/lib/e2p/getversion.c
@@ -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
index 0000000..52c16a1
--- /dev/null
+++ b/lib/e2p/iod.c
@@ -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
index 0000000..982f044
--- /dev/null
+++ b/lib/e2p/ls.c
@@ -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
index 0000000..efc74b3
--- /dev/null
+++ b/lib/e2p/pe.c
@@ -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
index 0000000..58f05de
--- /dev/null
+++ b/lib/e2p/pf.c
@@ -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
index 0000000..441d6dc
--- /dev/null
+++ b/lib/e2p/ps.c
@@ -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
index 0000000..c1e9fcb
--- /dev/null
+++ b/lib/e2p/setflags.c
@@ -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
index 0000000..a6da31e
--- /dev/null
+++ b/lib/e2p/setversion.c
@@ -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
index 0000000..c0ebdfb
--- /dev/null
+++ b/lib/et/.depend
@@ -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
index 0000000..6b4cd47
--- /dev/null
+++ b/lib/et/Makefile
@@ -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
index 0000000..ee4375b
--- /dev/null
+++ b/lib/et/com_err.3
@@ -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
index 0000000..9f4ba5f
--- /dev/null
+++ b/lib/et/com_err.c
@@ -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
index 0000000..54904c3
--- /dev/null
+++ b/lib/et/com_err.h
@@ -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
index 0000000..2f4b266
--- /dev/null
+++ b/lib/et/com_err.texinfo
@@ -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#=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
index 0000000..f17a278
--- /dev/null
+++ b/lib/et/compile_et.1
@@ -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
index 0000000..fdd249e
--- /dev/null
+++ b/lib/et/compile_et.sh
@@ -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
index 0000000..e3de35c
--- /dev/null
+++ b/lib/et/config_script
@@ -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
index 0000000..043b02e
--- /dev/null
+++ b/lib/et/error_message.c
@@ -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
index 0000000..78f7db2
--- /dev/null
+++ b/lib/et/error_table.h
@@ -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
index 0000000..e3d4c91
--- /dev/null
+++ b/lib/et/et_c.awk
@@ -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
index 0000000..d7688e9
--- /dev/null
+++ b/lib/et/et_h.awk
@@ -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
index 0000000..19da71d
--- /dev/null
+++ b/lib/et/et_name.c
@@ -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
index 0000000..856f0fd
--- /dev/null
+++ b/lib/et/init_et.c
@@ -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
index 0000000..112c016
--- /dev/null
+++ b/lib/et/internal.h
@@ -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
index 0000000..2f7eb29
--- /dev/null
+++ b/lib/et/mit-sipb-copyright.h
@@ -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
index 0000000..838160c
--- /dev/null
+++ b/lib/et/texinfo.tex
@@ -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 `\=\other
+\catcode `\=\other
+\catcode `\^^C=\other
+\catcode `\^^D=\other
+\catcode `\^^E=\other
+\catcode `\^^F=\other
+\catcode `\^^G=\other
+\catcode `\^^H=\other
+\catcode `\=\other
+\catcode `\^^L=\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
+\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
index 0000000..94f0fb5
--- /dev/null
+++ b/lib/et/vfprintf.c
@@ -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
index 0000000..653e191
--- /dev/null
+++ b/lib/ext2fs/.depend
@@ -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
index 0000000..82c7280
--- /dev/null
+++ b/lib/ext2fs/Makefile
@@ -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
index 0000000..c456ad1
--- /dev/null
+++ b/lib/ext2fs/alloc.c
@@ -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
index 0000000..5e8cd43
--- /dev/null
+++ b/lib/ext2fs/badblocks.c
@@ -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
index 0000000..d345f1d
--- /dev/null
+++ b/lib/ext2fs/bb_inode.c
@@ -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
index 0000000..c12433a
--- /dev/null
+++ b/lib/ext2fs/bitmaps.c
@@ -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
index 0000000..a53d8ee
--- /dev/null
+++ b/lib/ext2fs/bitops.c
@@ -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
index 0000000..c01cc86
--- /dev/null
+++ b/lib/ext2fs/bitops.h
@@ -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
index 0000000..d2c87ce
--- /dev/null
+++ b/lib/ext2fs/block.c
@@ -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
index 0000000..d25f312
--- /dev/null
+++ b/lib/ext2fs/closefs.c
@@ -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
index 0000000..1bc3f49
--- /dev/null
+++ b/lib/ext2fs/expanddir.c
@@ -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
index 0000000..86bfcd3
--- /dev/null
+++ b/lib/ext2fs/ext2_err.c
@@ -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
index 0000000..69eacda
--- /dev/null
+++ b/lib/ext2fs/ext2_err.et
@@ -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
index 0000000..1e72ced
--- /dev/null
+++ b/lib/ext2fs/ext2_err.h
@@ -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
index 0000000..998527a
--- /dev/null
+++ b/lib/ext2fs/ext2fs.h
@@ -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
index 0000000..ecd169a
--- /dev/null
+++ b/lib/ext2fs/freefs.c
@@ -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
index 0000000..591af6d
--- /dev/null
+++ b/lib/ext2fs/get_pathname.c
@@ -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
index 0000000..e7e07c4
--- /dev/null
+++ b/lib/ext2fs/initialize.c
@@ -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
index 0000000..6ec7387
--- /dev/null
+++ b/lib/ext2fs/inline.c
@@ -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
index 0000000..ba3cee8
--- /dev/null
+++ b/lib/ext2fs/inode.c
@@ -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
index 0000000..fd054f8
--- /dev/null
+++ b/lib/ext2fs/io.h
@@ -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
index 0000000..f0dbbc5
--- /dev/null
+++ b/lib/ext2fs/link.c
@@ -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
index 0000000..03e49d8
--- /dev/null
+++ b/lib/ext2fs/mkdir.c
@@ -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
index 0000000..3bb6d57
--- /dev/null
+++ b/lib/ext2fs/namei.c
@@ -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
index 0000000..948bad9
--- /dev/null
+++ b/lib/ext2fs/newdir.c
@@ -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
index 0000000..b63b7aa
--- /dev/null
+++ b/lib/ext2fs/openfs.c
@@ -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
index 0000000..65663a0
--- /dev/null
+++ b/lib/ext2fs/read_bb.c
@@ -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
index 0000000..db7b910
--- /dev/null
+++ b/lib/ext2fs/read_bb_file.c
@@ -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
index 0000000..1137870
--- /dev/null
+++ b/lib/ext2fs/unix_io.c
@@ -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
index 0000000..64a78dc
--- /dev/null
+++ b/lib/ss/.depend
@@ -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
index 0000000..af82f91
--- /dev/null
+++ b/lib/ss/Makefile
@@ -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
index 0000000..e3de35c
--- /dev/null
+++ b/lib/ss/config_script
@@ -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
index 0000000..e0d1572
--- /dev/null
+++ b/lib/ss/copyright.h
@@ -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
index 0000000..872f6e0
--- /dev/null
+++ b/lib/ss/ct_c.awk
@@ -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
index 0000000..8d6452b
--- /dev/null
+++ b/lib/ss/ct_c.sed
@@ -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
index 0000000..dd6341c
--- /dev/null
+++ b/lib/ss/data.c
@@ -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
index 0000000..3b7165a
--- /dev/null
+++ b/lib/ss/error.c
@@ -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
index 0000000..9442f33
--- /dev/null
+++ b/lib/ss/execute_cmd.c
@@ -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
index 0000000..ad3b90b
--- /dev/null
+++ b/lib/ss/help.c
@@ -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
index 0000000..678bbcd
--- /dev/null
+++ b/lib/ss/invocation.c
@@ -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
index 0000000..14877bb
--- /dev/null
+++ b/lib/ss/list_rqs.c
@@ -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
index 0000000..13844a0
--- /dev/null
+++ b/lib/ss/listen.c
@@ -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
index 0000000..ffcfc38
--- /dev/null
+++ b/lib/ss/mit-sipb-copyright.h
@@ -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
index 0000000..eda3888
--- /dev/null
+++ b/lib/ss/mk_cmds.sh
@@ -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
index 0000000..b951fa6
--- /dev/null
+++ b/lib/ss/pager.c
@@ -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
index 0000000..e1dec31
--- /dev/null
+++ b/lib/ss/parse.c
@@ -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
index 0000000..bc95d82
--- /dev/null
+++ b/lib/ss/prompt.c
@@ -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
index 0000000..b15ba91
--- /dev/null
+++ b/lib/ss/request_tbl.c
@@ -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
index 0000000..bfe69f1
--- /dev/null
+++ b/lib/ss/requests.c
@@ -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
index 0000000..4fa3ebe
--- /dev/null
+++ b/lib/ss/ss.h
@@ -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
index 0000000..7b97a00
--- /dev/null
+++ b/lib/ss/ss_err.c
@@ -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
index 0000000..80e9dfa
--- /dev/null
+++ b/lib/ss/ss_err.et
@@ -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
index 0000000..02ab507
--- /dev/null
+++ b/lib/ss/ss_err.h
@@ -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
index 0000000..4b9ea23
--- /dev/null
+++ b/lib/ss/ss_internal.h
@@ -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
index 0000000..d0f0ccb
--- /dev/null
+++ b/lib/ss/std_rqs.c
@@ -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
index 0000000..500288a
--- /dev/null
+++ b/lib/ss/std_rqs.ct
@@ -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
index 0000000..502256d
--- /dev/null
+++ b/lib/ss/test_ss.c
@@ -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
index 0000000..40b033a
--- /dev/null
+++ b/misc/.depend
@@ -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
index 0000000..3b37dc7
--- /dev/null
+++ b/misc/Makefile
@@ -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
index 0000000..080ca5b
--- /dev/null
+++ b/misc/badblocks.8
@@ -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
index 0000000..0560e67
--- /dev/null
+++ b/misc/badblocks.c
@@ -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
index 0000000..6a8e119
--- /dev/null
+++ b/misc/chattr.1
@@ -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
index 0000000..63c8108
--- /dev/null
+++ b/misc/chattr.c
@@ -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
index 0000000..30a90b5
--- /dev/null
+++ b/misc/dumpe2fs.8
@@ -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
index 0000000..fc0c45b
--- /dev/null
+++ b/misc/dumpe2fs.c
@@ -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
index 0000000..620a7fc
--- /dev/null
+++ b/misc/fsck.8
@@ -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
index 0000000..eb01fc5
--- /dev/null
+++ b/misc/fsck.c
@@ -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
index 0000000..b79714b
--- /dev/null
+++ b/misc/fsck.h
@@ -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
index 0000000..51a0d5a
--- /dev/null
+++ b/misc/lsattr.1
@@ -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
index 0000000..ae337d6
--- /dev/null
+++ b/misc/lsattr.c
@@ -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
index 0000000..5b1e5bc
--- /dev/null
+++ b/misc/mke2fs.8
@@ -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
index 0000000..9d36ee9
--- /dev/null
+++ b/misc/mke2fs.c
@@ -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
index 0000000..b566318
--- /dev/null
+++ b/misc/mklost+found.8
@@ -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
index 0000000..299e47c
--- /dev/null
+++ b/misc/mklost+found.c
@@ -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
index 0000000..3d99704
--- /dev/null
+++ b/misc/tune2fs.8
@@ -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
index 0000000..2f0d860
--- /dev/null
+++ b/misc/tune2fs.c
@@ -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
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"