From 3839e65723771b85975f4263102dd3ceec4523c0 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 26 Apr 1997 13:21:57 +0000 Subject: [PATCH] Many files: Checkin of e2fsprogs 0.5b --- INSTALL | 34 + MCONFIG | 57 + Makefile | 61 + README | 42 + debugfs/.depend | 36 + debugfs/Makefile | 42 + debugfs/debug_cmds.ct | 98 ++ debugfs/debugfs.8 | 133 ++ debugfs/debugfs.c | 1142 +++++++++++++++++ debugfs/debugfs.h | 18 + debugfs/icheck.c | 157 +++ debugfs/ncheck.c | 173 +++ debugfs/util.c | 94 ++ e2fsck/.depend | 229 ++++ e2fsck/CHANGES | 53 + e2fsck/Makefile | 82 ++ e2fsck/badblocks.c | 126 ++ e2fsck/dirinfo.c | 120 ++ e2fsck/e2fsck.8 | 127 ++ e2fsck/e2fsck.c | 481 +++++++ e2fsck/e2fsck.h | 176 +++ e2fsck/ehandler.c | 111 ++ e2fsck/flushb.c | 51 + e2fsck/images/README | 59 + e2fsck/images/baddir.img.gz | Bin 0 -> 14354 bytes e2fsck/images/badinode.img.gz | Bin 0 -> 1043 bytes e2fsck/images/badlkcnt.img.gz | Bin 0 -> 3830 bytes e2fsck/images/badroot.img.gz | Bin 0 -> 484 bytes e2fsck/images/badtable.img.gz | Bin 0 -> 995 bytes e2fsck/images/bbfile.img.gz | Bin 0 -> 5651 bytes e2fsck/images/bitmaps.img.gz | Bin 0 -> 635 bytes e2fsck/images/dirlink.img.gz | Bin 0 -> 497 bytes e2fsck/images/dup.img.gz | Bin 0 -> 3744 bytes e2fsck/images/dup2.img.gz | Bin 0 -> 14577 bytes e2fsck/images/end-bitmap.img.gz | Bin 0 -> 3763 bytes e2fsck/images/expand.img.gz | Bin 0 -> 13123 bytes e2fsck/images/lpf.img.gz | Bin 0 -> 15336 bytes e2fsck/images/mke2fs2b.img.gz | Bin 0 -> 563 bytes e2fsck/images/noroot.img.gz | Bin 0 -> 554 bytes e2fsck/images/test_script | 42 + e2fsck/images/test_script.log | 1289 +++++++++++++++++++ e2fsck/malloc.h | 231 ++++ e2fsck/mtrace.awk | 37 + e2fsck/mtrace.c | 158 +++ e2fsck/pass1.c | 894 +++++++++++++ e2fsck/pass1b.c | 640 ++++++++++ e2fsck/pass2.c | 631 ++++++++++ e2fsck/pass3.c | 684 ++++++++++ e2fsck/pass4.c | 70 ++ e2fsck/pass5.c | 328 +++++ e2fsck/util.c | 240 ++++ lib/e2p/.depend | 77 ++ lib/e2p/Makefile | 66 + lib/e2p/e2p.h | 20 + lib/e2p/fgetflags.c | 37 + lib/e2p/fgetversion.c | 37 + lib/e2p/fsetflags.c | 37 + lib/e2p/fsetversion.c | 37 + lib/e2p/getflags.c | 27 + lib/e2p/getversion.c | 27 + lib/e2p/iod.c | 42 + lib/e2p/ls.c | 52 + lib/e2p/pe.c | 39 + lib/e2p/pf.c | 40 + lib/e2p/ps.c | 31 + lib/e2p/setflags.c | 27 + lib/e2p/setversion.c | 27 + lib/et/.depend | 13 + lib/et/Makefile | 85 ++ lib/et/com_err.3 | 96 ++ lib/et/com_err.c | 127 ++ lib/et/com_err.h | 38 + lib/et/com_err.texinfo | 554 +++++++++ lib/et/compile_et.1 | 79 ++ lib/et/compile_et.sh | 11 + lib/et/config_script | 25 + lib/et/error_message.c | 72 ++ lib/et/error_table.h | 30 + lib/et/et_c.awk | 185 +++ lib/et/et_h.awk | 157 +++ lib/et/et_name.c | 43 + lib/et/init_et.c | 55 + lib/et/internal.h | 22 + lib/et/mit-sipb-copyright.h | 19 + lib/et/texinfo.tex | 2077 +++++++++++++++++++++++++++++++ lib/et/vfprintf.c | 47 + lib/ext2fs/.depend | 350 ++++++ lib/ext2fs/Makefile | 80 ++ lib/ext2fs/alloc.c | 125 ++ lib/ext2fs/badblocks.c | 130 ++ lib/ext2fs/bb_inode.c | 232 ++++ lib/ext2fs/bitmaps.c | 258 ++++ lib/ext2fs/bitops.c | 95 ++ lib/ext2fs/bitops.h | 172 +++ lib/ext2fs/block.c | 223 ++++ lib/ext2fs/closefs.c | 88 ++ lib/ext2fs/expanddir.c | 116 ++ lib/ext2fs/ext2_err.c | 68 + lib/ext2fs/ext2_err.et | 95 ++ lib/ext2fs/ext2_err.h | 46 + lib/ext2fs/ext2fs.h | 378 ++++++ lib/ext2fs/freefs.c | 36 + lib/ext2fs/get_pathname.c | 133 ++ lib/ext2fs/initialize.c | 189 +++ lib/ext2fs/inline.c | 26 + lib/ext2fs/inode.c | 231 ++++ lib/ext2fs/io.h | 59 + lib/ext2fs/link.c | 147 +++ lib/ext2fs/mkdir.c | 133 ++ lib/ext2fs/namei.c | 207 +++ lib/ext2fs/newdir.c | 57 + lib/ext2fs/openfs.c | 169 +++ lib/ext2fs/read_bb.c | 74 ++ lib/ext2fs/read_bb_file.c | 55 + lib/ext2fs/unix_io.c | 233 ++++ lib/ss/.depend | 69 + lib/ss/Makefile | 133 ++ lib/ss/config_script | 25 + lib/ss/copyright.h | 19 + lib/ss/ct_c.awk | 77 ++ lib/ss/ct_c.sed | 160 +++ lib/ss/data.c | 16 + lib/ss/error.c | 113 ++ lib/ss/execute_cmd.c | 219 ++++ lib/ss/help.c | 151 +++ lib/ss/invocation.c | 82 ++ lib/ss/list_rqs.c | 90 ++ lib/ss/listen.c | 138 ++ lib/ss/mit-sipb-copyright.h | 19 + lib/ss/mk_cmds.sh | 23 + lib/ss/pager.c | 91 ++ lib/ss/parse.c | 139 +++ lib/ss/prompt.c | 31 + lib/ss/request_tbl.c | 63 + lib/ss/requests.c | 48 + lib/ss/ss.h | 71 ++ lib/ss/ss_err.c | 51 + lib/ss/ss_err.et | 39 + lib/ss/ss_err.h | 29 + lib/ss/ss_internal.h | 120 ++ lib/ss/std_rqs.c | 108 ++ lib/ss/std_rqs.ct | 46 + lib/ss/test_ss.c | 133 ++ misc/.depend | 98 ++ misc/Makefile | 73 ++ misc/badblocks.8 | 66 + misc/badblocks.c | 276 ++++ misc/chattr.1 | 57 + misc/chattr.c | 261 ++++ misc/dumpe2fs.8 | 32 + misc/dumpe2fs.c | 162 +++ misc/fsck.8 | 152 +++ misc/fsck.c | 576 +++++++++ misc/fsck.h | 57 + misc/lsattr.1 | 40 + misc/lsattr.c | 143 +++ misc/mke2fs.8 | 104 ++ misc/mke2fs.c | 613 +++++++++ misc/mklost+found.8 | 30 + misc/mklost+found.c | 79 ++ misc/tune2fs.8 | 71 ++ misc/tune2fs.c | 192 +++ version.h | 10 + 163 files changed, 22904 insertions(+) create mode 100644 INSTALL create mode 100644 MCONFIG create mode 100644 Makefile create mode 100644 README create mode 100644 debugfs/.depend create mode 100644 debugfs/Makefile create mode 100644 debugfs/debug_cmds.ct create mode 100644 debugfs/debugfs.8 create mode 100644 debugfs/debugfs.c create mode 100644 debugfs/debugfs.h create mode 100644 debugfs/icheck.c create mode 100644 debugfs/ncheck.c create mode 100644 debugfs/util.c create mode 100644 e2fsck/.depend create mode 100644 e2fsck/CHANGES create mode 100644 e2fsck/Makefile create mode 100644 e2fsck/badblocks.c create mode 100644 e2fsck/dirinfo.c create mode 100644 e2fsck/e2fsck.8 create mode 100644 e2fsck/e2fsck.c create mode 100644 e2fsck/e2fsck.h create mode 100644 e2fsck/ehandler.c create mode 100644 e2fsck/flushb.c create mode 100644 e2fsck/images/README create mode 100644 e2fsck/images/baddir.img.gz create mode 100644 e2fsck/images/badinode.img.gz create mode 100644 e2fsck/images/badlkcnt.img.gz create mode 100644 e2fsck/images/badroot.img.gz create mode 100644 e2fsck/images/badtable.img.gz create mode 100644 e2fsck/images/bbfile.img.gz create mode 100644 e2fsck/images/bitmaps.img.gz create mode 100644 e2fsck/images/dirlink.img.gz create mode 100644 e2fsck/images/dup.img.gz create mode 100644 e2fsck/images/dup2.img.gz create mode 100644 e2fsck/images/end-bitmap.img.gz create mode 100644 e2fsck/images/expand.img.gz create mode 100644 e2fsck/images/lpf.img.gz create mode 100644 e2fsck/images/mke2fs2b.img.gz create mode 100644 e2fsck/images/noroot.img.gz create mode 100644 e2fsck/images/test_script create mode 100644 e2fsck/images/test_script.log create mode 100644 e2fsck/malloc.h create mode 100644 e2fsck/mtrace.awk create mode 100644 e2fsck/mtrace.c create mode 100644 e2fsck/pass1.c create mode 100644 e2fsck/pass1b.c create mode 100644 e2fsck/pass2.c create mode 100644 e2fsck/pass3.c create mode 100644 e2fsck/pass4.c create mode 100644 e2fsck/pass5.c create mode 100644 e2fsck/util.c create mode 100644 lib/e2p/.depend create mode 100644 lib/e2p/Makefile create mode 100644 lib/e2p/e2p.h create mode 100644 lib/e2p/fgetflags.c create mode 100644 lib/e2p/fgetversion.c create mode 100644 lib/e2p/fsetflags.c create mode 100644 lib/e2p/fsetversion.c create mode 100644 lib/e2p/getflags.c create mode 100644 lib/e2p/getversion.c create mode 100644 lib/e2p/iod.c create mode 100644 lib/e2p/ls.c create mode 100644 lib/e2p/pe.c create mode 100644 lib/e2p/pf.c create mode 100644 lib/e2p/ps.c create mode 100644 lib/e2p/setflags.c create mode 100644 lib/e2p/setversion.c create mode 100644 lib/et/.depend create mode 100644 lib/et/Makefile create mode 100644 lib/et/com_err.3 create mode 100644 lib/et/com_err.c create mode 100644 lib/et/com_err.h create mode 100644 lib/et/com_err.texinfo create mode 100644 lib/et/compile_et.1 create mode 100644 lib/et/compile_et.sh create mode 100644 lib/et/config_script create mode 100644 lib/et/error_message.c create mode 100644 lib/et/error_table.h create mode 100644 lib/et/et_c.awk create mode 100644 lib/et/et_h.awk create mode 100644 lib/et/et_name.c create mode 100644 lib/et/init_et.c create mode 100644 lib/et/internal.h create mode 100644 lib/et/mit-sipb-copyright.h create mode 100644 lib/et/texinfo.tex create mode 100644 lib/et/vfprintf.c create mode 100644 lib/ext2fs/.depend create mode 100644 lib/ext2fs/Makefile create mode 100644 lib/ext2fs/alloc.c create mode 100644 lib/ext2fs/badblocks.c create mode 100644 lib/ext2fs/bb_inode.c create mode 100644 lib/ext2fs/bitmaps.c create mode 100644 lib/ext2fs/bitops.c create mode 100644 lib/ext2fs/bitops.h create mode 100644 lib/ext2fs/block.c create mode 100644 lib/ext2fs/closefs.c create mode 100644 lib/ext2fs/expanddir.c create mode 100644 lib/ext2fs/ext2_err.c create mode 100644 lib/ext2fs/ext2_err.et create mode 100644 lib/ext2fs/ext2_err.h create mode 100644 lib/ext2fs/ext2fs.h create mode 100644 lib/ext2fs/freefs.c create mode 100644 lib/ext2fs/get_pathname.c create mode 100644 lib/ext2fs/initialize.c create mode 100644 lib/ext2fs/inline.c create mode 100644 lib/ext2fs/inode.c create mode 100644 lib/ext2fs/io.h create mode 100644 lib/ext2fs/link.c create mode 100644 lib/ext2fs/mkdir.c create mode 100644 lib/ext2fs/namei.c create mode 100644 lib/ext2fs/newdir.c create mode 100644 lib/ext2fs/openfs.c create mode 100644 lib/ext2fs/read_bb.c create mode 100644 lib/ext2fs/read_bb_file.c create mode 100644 lib/ext2fs/unix_io.c create mode 100644 lib/ss/.depend create mode 100644 lib/ss/Makefile create mode 100644 lib/ss/config_script create mode 100644 lib/ss/copyright.h create mode 100644 lib/ss/ct_c.awk create mode 100644 lib/ss/ct_c.sed create mode 100644 lib/ss/data.c create mode 100644 lib/ss/error.c create mode 100644 lib/ss/execute_cmd.c create mode 100644 lib/ss/help.c create mode 100644 lib/ss/invocation.c create mode 100644 lib/ss/list_rqs.c create mode 100644 lib/ss/listen.c create mode 100644 lib/ss/mit-sipb-copyright.h create mode 100644 lib/ss/mk_cmds.sh create mode 100644 lib/ss/pager.c create mode 100644 lib/ss/parse.c create mode 100644 lib/ss/prompt.c create mode 100644 lib/ss/request_tbl.c create mode 100644 lib/ss/requests.c create mode 100644 lib/ss/ss.h create mode 100644 lib/ss/ss_err.c create mode 100644 lib/ss/ss_err.et create mode 100644 lib/ss/ss_err.h create mode 100644 lib/ss/ss_internal.h create mode 100644 lib/ss/std_rqs.c create mode 100644 lib/ss/std_rqs.ct create mode 100644 lib/ss/test_ss.c create mode 100644 misc/.depend create mode 100644 misc/Makefile create mode 100644 misc/badblocks.8 create mode 100644 misc/badblocks.c create mode 100644 misc/chattr.1 create mode 100644 misc/chattr.c create mode 100644 misc/dumpe2fs.8 create mode 100644 misc/dumpe2fs.c create mode 100644 misc/fsck.8 create mode 100644 misc/fsck.c create mode 100644 misc/fsck.h create mode 100644 misc/lsattr.1 create mode 100644 misc/lsattr.c create mode 100644 misc/mke2fs.8 create mode 100644 misc/mke2fs.c create mode 100644 misc/mklost+found.8 create mode 100644 misc/mklost+found.c create mode 100644 misc/tune2fs.8 create mode 100644 misc/tune2fs.c create mode 100644 version.h diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..b053c6c8 --- /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 00000000..e728fc63 --- /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 00000000..5437a135 --- /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 00000000..787bd204 --- /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 +and Remy . diff --git a/debugfs/.depend b/debugfs/.depend new file mode 100644 index 00000000..0788c389 --- /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 00000000..65b32aef --- /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 00000000..cd7faf17 --- /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 00000000..3d03e6bd --- /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 . +.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 00000000..b92746a0 --- /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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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] "; + 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 "; + 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(¶m, 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, ¶m, 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 + * '/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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 "); + 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 00000000..f7f5f086 --- /dev/null +++ b/debugfs/debugfs.h @@ -0,0 +1,18 @@ +/* + * debugfs.h --- header file for the debugfs program + */ + +#include +#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 00000000..848c76a3 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ..."); + 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\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 00000000..062e7c53 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ..."); + 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\n", iinfo->ino); + continue; + } + printf("%ld\t%s\n", iinfo->ino, iinfo->pathname ? + iinfo->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 00000000..24957fb5 --- /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 +#include +#include +#include +#include + +#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 , 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 00000000..e48c1af4 --- /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 00000000..fa135b6d --- /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 00000000..c0c64c63 --- /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 00000000..6dff23d9 --- /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 + +#include +#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 00000000..101ccee7 --- /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 +#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 00000000..d79903c3 --- /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 . +.SH SEE ALSO +.BR mke2fs (8), +.BR tune2fs (8) diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c new file mode 100644 index 00000000..37d202b5 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 00000000..a25f461a --- /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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..96aedfb8 --- /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 +#include +#include +#include +#include +#include + +#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 00000000..eba4e85d --- /dev/null +++ b/e2fsck/flushb.c @@ -0,0 +1,51 @@ +/* + * flushb.c --- This routine flushes the disk buffers for a disk + */ + +#include +#include +#include +#include +#include +#include + +#include + +#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 00000000..bd111fdb --- /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 0000000000000000000000000000000000000000..c7af6c58e97392ddd05bf2d1567927f6c4c29c36 GIT binary patch literal 14354 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 APXGV_ literal 0 HcmV?d00001 diff --git a/e2fsck/images/badinode.img.gz b/e2fsck/images/badinode.img.gz new file mode 100644 index 0000000000000000000000000000000000000000..7d10bc1d87d73f17ecde36f523d197c148f36b16 GIT binary patch literal 1043 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 Z_p@*P^SA!L;P$O;HWcQO4M;u%_#gZApWy%i literal 0 HcmV?d00001 diff --git a/e2fsck/images/badroot.img.gz b/e2fsck/images/badroot.img.gz new file mode 100644 index 0000000000000000000000000000000000000000..57241055bb4f1bdd9eae2bf375ee6a4ffceaf452 GIT binary patch literal 484 zcmb2|=HQt8WQPtDb5deTQGR}jUS@7O!`s_uvxEaB*dAO~(d+qY-?Yv~r2JHX{=y5X zv91NNvp891Np^O=xODqt)gGRu+_5F%`wM+MH*z~_w%DBikmfYQpx}XRahk`p%*@R< zx0RgMTpIYq?MY~gz)jEWqSiND_7`S0zY&m+&&w{QF}_dGWB>)NkB z-*^7xXK47pAol#bC6BImnJ<;U>!-!_m??Vk^e^&X;{QATXZ*|lMgBs)1A@`Wd!eN6 z@Av<^SH7+PyuZQm)$+@~?*93?BQ9j|xBB(*yY`x_eXgv`&cMJhd-4BeHnuC5r_Q_n zGb2dX?#aW82K#lsb^rPG__on|-_uzeryu{SBmewat=w6)_oub|S5;a{%g>+kcV8e2 UP&;+N4m*2B^~Z@x3=v1PD-n+NhZ>eU{zABNz-;DY|M40 zT~R8jnX@+2BwpeOa}j4NWf`lNm~+HV6D&m}_$BgfzDxVxZhP*Y&wc)R9$cA|6N`)z z9Ck8O)ACZ8+3Eh7?9Y&u*|_cgokCaL`?Y_=b5jD@timLxNj)Uw}_E^q7>wtU)~8vYG(J$vhrh3%Cl2b5&Ys+intAu=}g{Cv<#I z8EDbJgsToFK1l|~IYu1eD&Xb}8IL6~#I;IMA3%jNP|q#UQ1Hr@J}}ZuveDYMUJNMl za{AAPhA)lbVKUGeb{C#1vckO2tKpftbqy`WHl1wC;TSQ_s`@w?Fxh|oj}watFv_1V z4X)t(qM*msLY$iiXm5Cj&H_1S7c5x(qTyzEMgUm~o-Zr3>kFf?C%JhWzuqoly`?3} zVtM*KM$zLj(A4DESmQku%pW9e!KcdwEN8SKS9;IdmdryrFK`7sEt=8|R?1J>%8MC; zL6*AdmtOf5kV0Al<&QUF!`TOK6xrt6^%TU~xdeCE z`HE=A5AgNp2K=}7#l62`nTeK7KzS(%Y7Vq;OV#n;KNPHb3Ln;b#7sR3aLa!CoL5+A zo;lvh+gVQQ|BE$x=T3ReY5CKcdTw>pP0&?TvN@lYXwLAfdvCQduQu_B)@nDoWu=$J3pSEU0 z-Ln`Wtn MXN-fu=qrO@j;#bT)^FA(uZHS&T-NQYe68t1}W@-(^l-duJjw^yB)|s DD*pzl literal 0 HcmV?d00001 diff --git a/e2fsck/images/bbfile.img.gz b/e2fsck/images/bbfile.img.gz new file mode 100644 index 0000000000000000000000000000000000000000..155363afb29cc54f99de861da3eebf238407310f GIT binary patch literal 5651 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 literal 0 HcmV?d00001 diff --git a/e2fsck/images/dup2.img.gz b/e2fsck/images/dup2.img.gz new file mode 100644 index 0000000000000000000000000000000000000000..f5fcd37a703e1c0985272ea9bc7b8fbf34248ae7 GIT binary patch literal 14577 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 literal 0 HcmV?d00001 diff --git a/e2fsck/images/end-bitmap.img.gz b/e2fsck/images/end-bitmap.img.gz new file mode 100644 index 0000000000000000000000000000000000000000..b83478ffc84b8994b79dce6c2eb387b319c552d1 GIT binary patch literal 3763 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 E0DUHqMF0Q* literal 0 HcmV?d00001 diff --git a/e2fsck/images/lpf.img.gz b/e2fsck/images/lpf.img.gz new file mode 100644 index 0000000000000000000000000000000000000000..527c09bfe0fb025af2f98ca7664437821cd201c8 GIT binary patch literal 15336 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 Ssv-U--=)Kr>lh|5G5`P~KM4o` literal 0 HcmV?d00001 diff --git a/e2fsck/images/noroot.img.gz b/e2fsck/images/noroot.img.gz new file mode 100644 index 0000000000000000000000000000000000000000..3e597f3885167cf2198cf052d17b2fda388f9667 GIT binary patch literal 554 zcmb2|=HLj;xuV0woR?pepI@SvnVZh=_Rje%;Xo1g2i7xp8T4MwYTaR^=gPUSDSP^^ zVnt2WEsNM@apcvqirY16#~%t0D0q2DT))wa2Ri!KcJ&~3oU@3mHYfgX6iuJSOdSbfX{5kmJa!-Bbnd->pJB=>O{a?2x z^H26G`<`9hR%d_bU*ErN*{}8U!f$^ryfXJ{X57_v^|ifUH>U?~_xx&av2X9O_gCr# zO=rt|k30R3pCMy)UwXI6y7SxjPuXiCcU$j*WZ}Q%{~iCouD|fV;UD`K`vw0Q|MI`6 zclgizOa8+D11G0f@B91nzvHT3_VxM+>R&G}zFAY4Y*qa$W&N*t&wg+6xqS0X8#4n# zLvTvLk)QSZ_Fpxanps}7W7qMk3b{*;{yS)M|MjcfojarI1o*ErF+jkB|EE9yIs2#n zpU!~|^ZwtD`Wtul|MRE(Yc2o(k%1~HD7tgoen$VJjn> $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 00000000..c583fe5d --- /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: + (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: + (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: + (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 00000000..3e46718e --- /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 +#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 /* Harmless, gets __GNU_LIBRARY__ defined. */ + +#if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS) || defined(USG) +#include +#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 +#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 00000000..7e96b8ac --- /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 00000000..8553a64b --- /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 + +#ifndef __GNU_LIBRARY__ +extern char *getenv (); +#else +#include +#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 00000000..2f23b9d6 --- /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 + +#include +#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 00000000..dd657bfa --- /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 + +#include +#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] = +{ + "", /* 0 */ + "", /* 1 */ + "/", /* 2 */ + "", /* 3 */ + "", /* 4 */ + "", /* 5 */ + "" /* 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, "", 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 00000000..327cf16d --- /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 00000000..b34acd2a --- /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 00000000..290e1b95 --- /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 00000000..cd0cf5b7 --- /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 00000000..c9e63960 --- /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 +#include +#include +#include +#include +#include + +#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 = ""; + else if (def == 0) + defstr = ""; + 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 00000000..12950ef5 --- /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 00000000..e890bb5f --- /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 00000000..d459e87d --- /dev/null +++ b/lib/e2p/e2p.h @@ -0,0 +1,20 @@ +#include +#include + +#include + +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 00000000..95b0bdc8 --- /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 + * 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 +#include +#include +#include + +#include + +#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 00000000..73429f2a --- /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 + * 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 +#include +#include +#include + +#include + +#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 00000000..180d48f5 --- /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 + * 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 +#include +#include +#include + +#include + +#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 00000000..1bb8acca --- /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 + * 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 +#include +#include +#include + +#include + +#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 00000000..4e537490 --- /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 + * 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 +#include + +#include + +#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 00000000..04dc0f75 --- /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 + * 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 +#include + +#include + +#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 00000000..52c16a13 --- /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 + * 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 + +#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 00000000..982f0443 --- /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 + * 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 +#include + +#include + +#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 00000000..efc74b3a --- /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 + * 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 + +#include + +#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 00000000..58f05de1 --- /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 + * 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 +#include + +#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 00000000..441d6dc8 --- /dev/null +++ b/lib/e2p/ps.c @@ -0,0 +1,31 @@ +/* + * ps.c - Print filesystem state + * + * Copyright (C) 1993, 1994 Remy Card + * 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 + +#include + +#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 00000000..c1e9fcbb --- /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 + * 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 +#include + +#include + +#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 00000000..a6da31e2 --- /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 + * 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 +#include + +#include + +#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 00000000..c0ebdfbd --- /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 00000000..6b4cd476 --- /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 00000000..ee4375b0 --- /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 +.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 00000000..9f4ba5fa --- /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 +#include "mit-sipb-copyright.h" + +#if __STDC__ || defined(STDARG_PROTOTYPES) +#include +#else +#include +#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 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 00000000..54904c35 --- /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 +#else +#include +#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 00000000..2f4b2661 --- /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{}. 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 + +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 + +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 +#include +#include + +/* 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{}. 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{} is not +available, and therefore @code{} must be used. If the symbol +@code{VARARGS} is defined (e.g., in the makefile), @code{} 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 00000000..f17a278b --- /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 00000000..fdd249e8 --- /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 00000000..e3de35c8 --- /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 [] [] +# + +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 00000000..043b02eb --- /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 +#include +#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<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 00000000..78f7db20 --- /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 00000000..e3d4c914 --- /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 00000000..d7688e97 --- /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 00000000..19da71d3 --- /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 00000000..856f0fdc --- /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 +#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 00000000..112c0161 --- /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 + +#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 00000000..2f7eb295 --- /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 00000000..838160c9 --- /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 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\}\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 00000000..94f0fb58 --- /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 +#include + +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 00000000..653e1916 --- /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 00000000..82c72806 --- /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 00000000..c456ad13 --- /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 +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..5e8cd436 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..d345f1dd --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..c12433a6 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..a53d8ee8 --- /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 , Copyright 1992, Linus Torvalds. + */ + +#include +#include +#include +#include + +#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 00000000..c01cc866 --- /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 , 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 00000000..d2c87cef --- /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 +#include +#include +#include +#include +#include + +#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 00000000..d25f312b --- /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 +#include +#include +#include + +#include +#include + +#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 00000000..1bc3f491 --- /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 +#include +#include +#include +#include +#include + +#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 00000000..86bfcd34 --- /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 00000000..69eacda6 --- /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 00000000..1e72cedc --- /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 00000000..998527a1 --- /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 00000000..ecd169af --- /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 +#include +#include + +#include +#include + +#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 00000000..591af6d4 --- /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 +#include +#include +#include +#include +#include + +#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 00000000..e7e07c46 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..6ec7387a --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define INCLUDE_INLINE_FUNCS + +#include "ext2fs.h" + diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c new file mode 100644 index 00000000..ba3cee8a --- /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 +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..fd054f84 --- /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 00000000..f0dbbc51 --- /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 +#include +#include +#include +#include +#include + +#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 00000000..03e49d8f --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..3bb6d570 --- /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 +#include +#include +#include +#include +#include + +#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 00000000..948bad9f --- /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 +#include +#include +#include +#include +#include + +#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 00000000..b63b7aaa --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..65663a0f --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..db7b9107 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 00000000..1137870e --- /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 +#include +#include +#include +#include +#include +#include +#include + +#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 00000000..64a78dc8 --- /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 00000000..af82f913 --- /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 00000000..e3de35c8 --- /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 [] [] +# + +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 00000000..e0d15722 --- /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 00000000..872f6e00 --- /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 " > 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 00000000..8d6452be --- /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 +# +#(for each request definition) +# BOR +# sub: +# hlp: +# cmd: +# opt: