Imported Upstream version 0.4b37 upstream/0.4b37
authorBdale Garbee <bdale@gag.com>
Tue, 20 May 2008 05:04:23 +0000 (23:04 -0600)
committerBdale Garbee <bdale@gag.com>
Tue, 20 May 2008 05:04:23 +0000 (23:04 -0600)
93 files changed:
CHANGES [new file with mode: 0644]
COPYRIGHT [new file with mode: 0644]
INSTALL [new file with mode: 0644]
KNOWNBUGS [new file with mode: 0644]
MAINTAINERS [new file with mode: 0644]
MCONFIG.in [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
README [new file with mode: 0644]
REPORTING-BUGS [new file with mode: 0644]
THANKS [new file with mode: 0644]
TODO [new file with mode: 0644]
common/Makefile.in [new file with mode: 0644]
common/dumprmt.c [new file with mode: 0644]
compat/include/Makefile.in [new file with mode: 0644]
compat/include/bsdcompat.h [new file with mode: 0644]
compat/include/bylabel.h [new file with mode: 0644]
compat/include/compaterr.h [new file with mode: 0644]
compat/include/compatglob.h [new file with mode: 0644]
compat/include/compatlfs.h [new file with mode: 0644]
compat/include/darwin.h [new file with mode: 0644]
compat/include/lzoconf.h [new file with mode: 0644]
compat/include/minilzo.h [new file with mode: 0644]
compat/include/pathnames.h [new file with mode: 0644]
compat/include/protocols/dumprestore.h [new file with mode: 0644]
compat/include/rmtflags.h [new file with mode: 0644]
compat/include/system.h [new file with mode: 0644]
compat/lib/Makefile.in [new file with mode: 0644]
compat/lib/README.LZO [new file with mode: 0644]
compat/lib/README2.LZO [new file with mode: 0644]
compat/lib/bylabel.c [new file with mode: 0644]
compat/lib/compaterr.c [new file with mode: 0644]
compat/lib/compatglob.c [new file with mode: 0644]
compat/lib/minilzo.c [new file with mode: 0644]
compat/lib/rmtflags.c [new file with mode: 0644]
compat/lib/system.c [new file with mode: 0644]
config.guess [new file with mode: 0755]
config.h.in [new file with mode: 0644]
config.sub [new file with mode: 0755]
configure [new file with mode: 0755]
configure.in [new file with mode: 0644]
depfix.sed [new file with mode: 0644]
dump.lsm [new file with mode: 0644]
dump.spec [new file with mode: 0644]
dump/Makefile.in [new file with mode: 0644]
dump/dump.8.in [new file with mode: 0644]
dump/dump.h [new file with mode: 0644]
dump/itime.c [new file with mode: 0644]
dump/main.c [new file with mode: 0644]
dump/optr.c [new file with mode: 0644]
dump/tape.c [new file with mode: 0644]
dump/traverse.c [new file with mode: 0644]
dump/unctime.c [new file with mode: 0644]
examples/cron_dump_to_disk/README [new file with mode: 0644]
examples/cron_dump_to_disk/backup [new file with mode: 0755]
examples/cron_dump_to_disk/backup_rotate [new file with mode: 0755]
examples/cron_dump_to_disk/backupskel.tar.gz [new file with mode: 0644]
examples/cron_dump_to_disk/crontab_entries.txt [new file with mode: 0644]
examples/dump_on_cd/README [new file with mode: 0644]
examples/dump_on_cd/dump_userinfo.sh [new file with mode: 0755]
examples/dump_on_cd/start_dump.sh [new file with mode: 0755]
examples/dump_on_cd/verify_dump.sh [new file with mode: 0755]
examples/dump_on_cd_2/DE/backup_CD [new file with mode: 0644]
examples/dump_on_cd_2/DE/backup_DVD [new file with mode: 0644]
examples/dump_on_cd_2/DE/dump_userexit_CD [new file with mode: 0644]
examples/dump_on_cd_2/DE/dump_userexit_DVD [new file with mode: 0644]
examples/dump_on_cd_2/EN/backup_CD [new file with mode: 0644]
examples/dump_on_cd_2/EN/backup_DVD [new file with mode: 0644]
examples/dump_on_cd_2/EN/dump_userexit_CD [new file with mode: 0644]
examples/dump_on_cd_2/EN/dump_userexit_DVD [new file with mode: 0644]
examples/dump_on_cd_2/README [new file with mode: 0644]
examples/dump_on_remote_cd/README [new file with mode: 0644]
examples/dump_on_remote_cd/dump-to-remote-cd [new file with mode: 0755]
examples/dump_on_remote_cd/get-dumpdata-to-cdrecord [new file with mode: 0755]
examples/encrypted_rmt/README [new file with mode: 0644]
examples/howto/ultra-mini-howto [new file with mode: 0644]
examples/remote_backup_ssh/backitup [new file with mode: 0644]
install-sh [new file with mode: 0755]
linux-1.2.x.patch [new file with mode: 0644]
restore/Makefile.in [new file with mode: 0644]
restore/dirs.c [new file with mode: 0644]
restore/extern.h [new file with mode: 0644]
restore/interactive.c [new file with mode: 0644]
restore/main.c [new file with mode: 0644]
restore/restore.8.in [new file with mode: 0644]
restore/restore.c [new file with mode: 0644]
restore/restore.h [new file with mode: 0644]
restore/symtab.c [new file with mode: 0644]
restore/tape.c [new file with mode: 0644]
restore/utilities.c [new file with mode: 0644]
rmt/Makefile.in [new file with mode: 0644]
rmt/cipher.c [new file with mode: 0644]
rmt/rmt.8.in [new file with mode: 0644]
rmt/rmt.c [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..501bc16
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,1380 @@
+$Id: CHANGES,v 1.254 2004/07/07 13:34:06 stelian Exp $
+
+Changes between versions 0.4b36 and 0.4b37 (released July 7, 2004)
+==================================================================
+
+1.     Added the --enable-staticz configure option which enables
+       dump and restore to be linked with static versions of
+       libz and libbz2 (and dynamic versions of all other libraries).
+       This will make Debian users happy, because libz and libbz2
+       were the only needed libraries living in /usr, all the
+       others live in /lib. In case of system emergency, it is 
+       better not to have to rely on an extra filesystem.
+       Thanks to Bdale Garbee <bdale@gag.com> for the suggestion.
+
+2.     Fix compilation on (at least the Linux Debian port to) AMD64.
+       (<ext2fs/ext2_types.h> defines some types (__s64 and __u64)
+       that are also defined by <linux/types.h> (<asm/types.h>) and 
+       they conflict).
+
+3.     Make dump's reading of the dumpdates file a bit more robust,
+       preventing dump from crashing when the dumpdates file has
+       been modified by hand.
+
+4.     Fixed some offset calculations in dump code which could 
+       lead to "bread lseek errors" on large filesystems. Thanks
+       to Bruce Lowekamp <lowekamp@users.sourceforge.net> for
+       reporting this bug and debugging the issue.
+
+5.     Made dump use the blkid library when searching for devices
+       by label or uuid instead of dump's own routines.
+
+6.     Corrected a bug in dump where a wrong LABEL=... line in
+       /etc/fstab could prevent dump from dumping unrelated 
+       filesystems. Thanks to Bruce Lowekamp
+       <lowekamp@users.sourceforge.net> for reporting the bug.
+
+Changes between versions 0.4b35 and 0.4b36 (released April 21, 2004)
+====================================================================
+
+1.     Fixed dump compilation with old gcc versions. Thanks to
+       Mike Castle <dalgoda@users.sourceforge.net> for the patch.
+
+2.     Fixed some warnings (howmany, roundup, powerof2 redefined)
+       when compiling against a recent glibc version.
+
+3.     Fixed a bug in restore preventing the read of a dump tape
+       written with Solaris 7 ufsdump. Thanks to Patrick Higgins
+       <phiggins@transzap.com> for reporting the bug and providing 
+       the test case.
+
+4.     Changed dump to enable the creation of volumes of different
+       sizes in a single run (make -B accept a list of values).
+       Patch contributed by Florian Zumbiehl <florz@gmx.de>.
+
+5.     Use the glibc provided minor() and major() macros instead
+       of our own bitmask implementation. This should be safe for
+       when the major/minor namespace will migrate to 32 bits.
+       Thanks to Zhang Jun <zhangjun@nanjing-fnst.com> for reporting
+       the bug.
+
+6.     Made explicit in the dump man page that dump will not create
+       a remote file, it will only write to an already existing one.
+
+7.     Another try at making size estimates better again.
+
+8.     Put back the inconditional running of the end-of-tape
+       script which was changed in 0.434 to be run only when -M
+       or multiple -f were NOT specified. Some users rely on this
+       feature even when it is combined with -M/-f.
+
+9.     Fixed restore when restoring huge backups (where rstdir...
+       temporary files are over 2GB). Thanks to 
+       Raphael Jaffey <rjaffey@artic.edu> for reporting this, 
+       debugging the issue and making the patch.
+
+10.    Made restore understand FreeBSD UFS2 tapes. Thanks to
+       David <vrtin@users.sourceforge.net> for submitting the bug
+       and providing a test case.
+
+11.    Made dump work with an arbitrary integer level (no more 10
+       levels only limitation). Thanks to Matthew
+       <msvincen@midway.uchicago.edu> for the patch.
+       
+Changes between versions 0.4b34 and 0.4b35 (released December 21, 2003)
+=======================================================================
+
+1.     Added a note in the dump man page saying that the default
+       blocksize can be 32 if -d is used with a high density argument.
+       Thanks to Antonios Christofides <A.Christofides@itia.ntua.gr>
+       for the patch.
+
+2.     Fixed configure to correctly understand CPPFLAGS, CFLAGS,
+       LDFLAGS environment variables. Thanks to Arcady Genkin
+       <antipode@users.sourceforge.net> for reporting the bug.
+
+3.     Made -e/-E options of dump accept an unlimited number of inodes
+       to be excluded, rather than a hardcoded maximum. Thanks to 
+       Dietrich Rothe <d-rothe@users.sourceforge.net> for the patch.
+
+4.     Updated the autoconf system to 2.50. Forced the -D_BSD_SOURCE
+       and -D_USE_BSD_SIGNAL defines in configure in order to solve
+       64bit build problems because quad_t is redifined with a 
+       different signature. Thanks to Mike Harris <mharris@redhat.com>
+       for reporting this bug.
+
+5.     Made restore build on Solaris, making possible to
+       restore Linux's "enhanced" tapes. Thanks to Uwe Gohlke
+       <uwe@ugsoft.de> for the patch.
+
+6.     Made an extension in the dump tape format capable of saving
+       MacOSX specific inode extensions. Uwe Gohlke <uwe@ugsoft.de>
+       wrote the extension and contributed the restore code back
+       into this codebase. The same extension mechanism will be
+       used in the future to save ACLs...
+
+7.     Made rmt work correctly with regard to QFA and local/remote
+       files and tapes. The remote access will however work only 
+       when the dump provided rmt version is used. If you want to
+       use another rmt server, please do not use the QFA feature.
+       Thanks to Uwe Gohlke <uwe@ugsoft.de> for the patch.
+
+Changes between versions 0.4b33 and 0.4b34 (released April 18, 2003)
+====================================================================
+
+1.     Fixed the INSTALL file to reflect the actual install paths.
+       Thanks to David Ronis <ronis@ronispc.chem.mcgill.ca> for
+       reporting the bug.
+
+2.     Fixed the configure script to only check for headers presence
+       instead of trying to compile them. This should fix issues
+       with old build environments. Thanks to Kari Lempiainen 
+       <kari@funky.pp.fi> for reporting the bug.
+
+3.     Fixed restore to correctly ignore sockets when comparing
+       a dump (as socket cannot be properly restored anyway). Thanks
+       to Gunther Reiszig <gunther@mit.edu> for reporting the bug.
+
+4.     Fixed restore to correctly access the archive file (-A argument)
+       even when using a remote tape. Thanks to Fabrice Bellet 
+       <fabrice@bellet.info> for reporting the bug.
+
+5.     Fixed (again) handling of long (largefile) seeks in rmt.
+       Thanks to Fabrice Bellet <fabrice@bellet.info> for reporting
+       the bug.
+
+6.     Fixed restore corner case when dealing with large block sizes
+       dump is able to write now (-b 1024). Thanks to Fabrice Bellet
+       <fabrice@bellet.info> for reporting the bug.
+
+7.     Fixed a bug preventing dump to access a filesystem having 
+       a label exactly 16 bytes in length. Thanks to <minduni@ti-edu.ch>
+       for reporting the bug.
+
+8.     Made dump store dump dates using explicit timezones, fixing a
+       problem with incremental dumps if the timezone is modified 
+       between the dumps. Thanks to Philippe Troin <phil@fifi.org> for
+       the bug report and the patch.
+
+9.     Fixed a bug encountered when dumping individual files (not full
+       filesystems or directories) and dangling symbolic links happen
+       to be in the list of files. For as far as dump is concerned,
+       dangling symbolic links are allowed, and are dumped as is.
+       Thanks to Jin-su Ahn <jsahn@ee.snu.ac.kr> for reporting the
+       bug and providing the fix.
+
+10.    Fixed open and creation modes and permissions for QFA and
+       table-of-contents files in dump and restore. Thanks to 
+       Philippe Troin <phil@fifi.org> for the patch.
+
+11.    Fixed the archive file descriptor handling enabling it to be 0.
+       This can happen in some cases when shell redirections are used.
+       Thanks to Philippe Troin <phil@fifi.org> for the patch.
+
+12.    Delayed the opening of archive file until after suid had been
+       dropped (fixing a possible security issue if dump is suid). 
+       Thanks to Philippe Troin <phil@fifi.org> for the patch.
+
+13.    Fixed the 'S' command handling in the rmt client part.
+       Thanks to Philippe Troin <phil@fifi.org> for the patch.
+       
+14.    Modified the end-of-tape script handling to print out statistics
+       (and stop the timer) before launching the eot script. Also, the eot
+       script does not get run anymore when using -M (which makes sense) or
+       when multiple tapes are listed on the command line 
+       (-f tape0,tape1,tapen) (which also makes sense).
+       Thanks to Philippe Troin <phil@fifi.org> for the patch.
+
+15.    Relicensed dump/restore under the 'revised' BSD license, as per
+       ftp://ftp.cs.berkeley.edu/ucb/4bsd/README.Impt.License.Change.
+
+16.    Added LZO compression to dump. This new compression method has
+       the advantage of being super fast, thus not killing tape streaming
+       on slow machines. Thanks to Helmut Jarausch 
+       <jarausch@igpm.rwth-aachen.de> for the patch and to 
+       Markus Oberhumer <markus@oberhumer.com> for giving special permission
+       to include his miniLZO project (GPL licensed) in dump/restore.
+
+17.    Some small buffer overruns fixes in rmt. Thanks to Antonomasia
+       <ant@notatla.demon.co.uk> for reporting the bugs.
+
+18.    Added a special rmt version which can do encryption when writing
+       to tape. Read examples/encrypted_rmt/README for details on
+       how to enable and configure it. Thanks to Ken Lalonde
+       <ken@globalremit.com> for the patch.
+
+19.    Made dump work with 2.5 kernel end of tape early warning semantics.
+       Thanks to Kai Makisara <Kai.Makisara@kolumbus.fi> for the patch.
+
+20.    Fixed a bug which caused dump -w|-W not to work anymore, because
+       the fs_freq and fs_passno fields in /etc/mtab are always set
+       to 0 0. Thanks to Trent Piepho <xyzzy@speakeasy.org> for 
+       reporting the bug.
+
+Changes between versions 0.4b32 and 0.4b33 (released February 10, 2003)
+=======================================================================
+
+1.     Added a note in the restore man page clarifying the question
+       'set the permissions on the current directory ?' asked by
+       restore at the end of treatment in -i and -x modes.
+
+2.     Fixed the endianess issues when reading compressed tapes.
+       Thanks to Dark Force <daq4th@users.sourceforge.net> for
+       reporting this bug and providing test cases.
+
+3.     Fixed the "ACL won't be dumped" warning message (which showed
+       an extra, unrelated error message). Thanks to Dragan Krnic
+       <dkrnic@lycos.com> for reporting this bug.
+
+4.     Made dump look first into /etc/mtab, then into /etc/fstab 
+       when searching for filesystem paths. Also fixed some problems
+       caused by binding mounts or multiple block device mounts.
+       Thanks to Matus Uhlar <uhlar@fantomas.sk>, Elliott Mitchell
+       <ehem@m5p.com>, Greg Edwards <gedwards@users.sourceforge.net>,
+       Brian Hoy <brian.hoy@opus.co.nz>. (fixes Debian bugs #147086
+       and #160305, Sourceforge bugs #618699 and #679832).
+
+5.     Made dump's -I option accept the value '0' meaning all the
+       read errors will be ignored. This can be useful when running
+       dump from unattended sessions (like cron jobs). Thanks to
+       John I Wang <jiwang@users.sourceforge.net> for the suggestion.
+
+6.     Fixed the output of dump to indicate 'blocks' instead of
+       'tape blocks' in the various messages (blocks are always
+       1 Kilobyte, tape blocks are 1 BK * '-b' argument), and 
+       made it clearly print the current blocksize at the start of
+       a dump. Thanks to Michal Szymanski <msz@astrouw.edu.pl> for
+       the suggestions.
+
+7.     Made rmt understand long (largefiles) seeks.
+
+8.     Fixed build with very old versions of libext2fs, where
+       EXT2_FT_* constants were undefined.
+
+9.     Made dump accept the dumpdates path on the command line
+       (-D file option) instead of using only the hardcoded one.
+       Thanks to Piete Brooks <pb22@users.sourceforge.net> for the
+       suggestion.
+
+10.    Enabled rmt, LFS, readline, QFA options by default in
+       ./configure. Updated the configure process (new versions
+       of config.guess, config.sub etc).
+
+Changes between versions 0.4b31 and 0.4b32 (released November 15, 2002)
+=======================================================================
+
+1.     Changed dump to use fcntl(F_SETLK) style locking instead
+       of flock() when locking the dumpdates file. With the old 
+       locking scheme, a local user having read rights on the 
+       dumpdates file could be able to do a Denial of Service attack
+       on dump. In order to lock the dumpdates file with the new
+       scheme, the user would need to have write access on the file.
+       Thanks to Richard Johnson <Richard.Johnson3@ey.com> for 
+       reporting the bug (originally a bugtraq post).
+
+2.     Fixed interactive 'ls' which caused spurious errors warnings
+       about 'undefined filetypes' detected. Thanks to Jorgen Ostling 
+       <jorgen_ostling@users.sourceforge.net> for reporting this 
+       bug.
+
+3.     Fixed dump's estimate when dealing with sparse inodes.
+
+4.     Modified dump to allow setting a blocksize bigger than 32kB
+       (raised the limit to 1024kB), because newer hardware needs
+       this for proper operation. Thanks to Dirk Traenapp
+       <dtraenapp@users.sourceforge.net> for reporting this.
+
+5.     Fixed a bug causing Dump to stop and report an error if an
+       inode number in the exclude file was followed by some amount
+       of whitespace. Thanks to Jeffrey Sofferin 
+       <sofferin@users.sourceforge.net> for reporting this bug.
+
+6.     Fixed a bug which caused restore, in some particular cases,
+       to ask some 'scary' questions and leave a bunch of RSTTMP
+       directories behind when restoring incremental tapes. Thanks
+       to Philippe Troin <phil@fifi.org> for reporting this bug and
+       providing the test cases.
+
+7.     Changed the wording when inodes are excluded from dump:
+       replaced 'Added inode 7 to exclude list' with
+       'Excluding inode 7 (resize inode) from dump', as suggested
+       by Elliott Mitchell <ehem@m5p.com> in a Debian bug report.
+
+Changes between versions 0.4b30 and 0.4b31 (released July 30, 2002)
+===================================================================
+
+1.     Fixed rmt open flags transmission (GNU's symbolic syntax over
+       rmt) which I broke in 0.4b29. Thanks to Eros Albertazzi
+       <eros@lamel.bo.cnr.it> for reporting the bug.
+
+Changes between versions 0.4b29 and 0.4b30 (released July 25, 2002)
+===================================================================
+
+1.     Made dump print out the ext2 logical block number in case of a read
+       error, which can be given as an argument to debugfs' ncheck command,
+       in order to find out the affected inode. Added note about this 
+       usage in dump's man page.
+
+2.     Fixed a problem in restore when reading tapes written on big
+       endian machines with very old versions of dump. The patch was
+       contributed by George Helffrich <george@geology.bristol.ac.uk>.
+
+3.     Fixed the tape length calculation when using large tapes
+       and compression. Thanks to Georg Lippold 
+       <g_lippold@sourceforge.net> for reporting the bug.
+
+4.     Added a new set of examples in dump_on_cd_2 directory, based
+       on dump_on_cd examples but somewhat enhanced, supporting DVD
+       media, and localized in english and german. Thanks to
+       Georg Lippold <g_lippold@sourceforge.net> for the new scripts.
+
+5.     Made dump save 32 bit UID/GID. Internally, this was achieved
+       by switching from the old BSD inode format to the new BSD 
+       inode format, which means that the tape format was changed.
+       However, since all restore versions out there should 
+       transparently support both inode formats, the change should
+       have no side effects. Thanks to John Yu <jky@cs.bu.edu> for
+       reporting the bug.
+
+6.     Fixed a lot of warnings in the code shown when compiling
+       with 'gcc -W'. Thanks to Matthias Andree 
+       <matthias.andree@stud.uni-dortmund.de> for reporting this.
+
+7.     Fixed a small markup bug in the dump man page. Thanks to
+       Eric S. Raymond <esr@minx.thyrsus.com> for submitting the
+       patch.
+
+8.     Rewrote entirely the man pages using the tmac.an macro
+       package (Linux man page format) instead of the original BSD
+       format. They should be now cleaner and easier to modify.
+
+Changes between versions 0.4b28 and 0.4b29 (released June 8, 2002)
+==================================================================
+
+1.     Fixed a problem in the rmt ioctl command, where ioctl's issued from
+       non Linux clients were misinterpreted. The description of the problem
+       (incompatible numbering in Linux mtio opcodes) is documented at
+       ftp://ftp.fokus.gmd.de/pub/unix/star/README.mtio . Thanks to
+       Jörg Schilling <schilling@fokus.gmd.de> for reporting this bug and
+       providing an excellent, cross-platform replacement for rmt in his
+       star package.
+
+2.     Fixed a bug reported by Andy Mentges <amentges@jumpline.com>
+       which caused restore to fail when the inode maps were not entirely
+       contained on the first volume (when using really small volumes or
+       when dumping a huge number of inodes).
+
+3.     Fixed a problem in dump, where files in subdirectories of directories 
+       that have the nodump flag set (or being excluded with -e/-E) were 
+       sometimes incorrectly dumped (instead of being excluded). The original
+       fix is from David C Lawrence <tale@dd.org> in the FreeBSD version 
+       of dump: http://www.FreeBSD.org/cgi/query-pr.cgi?pr=32414
+       Thanks to Ted Grzesik <tedgyz@roostme.com> for reporting the bug and 
+       help testing the patch.
+
+4.     Added some example scripts from Gerd Bavendiek <bav@epost.de>
+       which makes one able to pipe the output of dump, by the net, to
+       a remote CD-burner server.
+
+5.     Made dump use O_CREAT|O_TRUNC both locally and remotely (over rmt), 
+       and use GNU's symbolic syntax over rmt instead of numerical values
+       to assure multiple platform compatibility.
+
+6.     Documented the -d option in restore.
+
+7.     Added a -v (verbose) mode to dump. For now it just prints the number
+       of the inode being dumped, but this could evolve in future versions
+       to include interesting debugging output.
+
+8.     Added a -o flag to restore, which automatically restores the current
+       directory permissions in -i or -x mode, without asking the operator
+       whether to do so. Patch submitted by Tony Clayton <tonyc@e-smith.com>
+       and Peter Samuel <peters@e-smith.com>.
+
+Changes between versions 0.4b27 and 0.4b28 (released April 12, 2002)
+====================================================================
+
+1.     Fixed a bug in the QFA feature which could have caused 
+       a bad tape positionning on restore (causing extra delays in
+       restore). Credits go to Uwe Gohlke <uwe@ugsoft.de>.
+
+2.     Added a small note in the dump man page specifying that
+       there should be no white space between the option letter and
+       the -j or -z parameter, thanks to Kenneth Porter <shiva@well.com>
+
+3.     Made restore work with older versions of the readline library,
+       by checking in configure for several extended symbols. Restore
+       can now be compiled with a readline as old as the 2.0 release
+       (though it may be a good idea to upgrade it to a more recent
+       version...). Thanks to Andrew Donkin <ard@waikato.ac.nz> for
+       reporting the build failures.
+
+4.     Fixed a performance problem with the QFA file creation in
+       dump, which made unnecessary seeks on the tape slowing down
+       the dump. Thanks to Andrew Donkin <ard@waikato.ac.nz> for
+       reporting this issue.
+
+5.     Removed the inclusion of some kernel headers in the dump
+       source, which prevented the compile in some kernel/glibc
+       headers/architecture combination. Thanks to Bdale Garbee
+       <bdale@gag.com> for reporting the bug.
+
+6.     Added the appropriate error message when dump fails to
+       open the output file for writing. Thanks to Amith Varghese
+       <amithv@yahoo.com> for reporting this bug.
+
+7.     Made restore able to understand large Solaris ufsdump tapes 
+       (containing inodes bigger than 4194304). Sun have introduced
+       an "extension" to the dump tape format when dealing with
+       those inodes, which was uncorrectly handled by Linux restore.
+       Thanks to Uwe Gohlke <uwe@ugsoft.de> for reporting the bug and
+       providing a test case.
+
+8.     Added the -m parameter to dump which optimises the output for
+       inodes having been changed but not modified since the last dump
+       ('changed' and 'modified' have the meaning defined in stat(2)).
+       For those inodes, dump will save only the metadata, instead of
+       saving the entire inode contents. Inodes which are either 
+       directories or have been modified since the last dump are saved
+       in a regular way.  Uses of this flag must be consistent, meaning
+       that either every dump in an incremental dump set have the flag,
+       or no one has it.
+
+Changes between versions 0.4b26 and 0.4b27 (released February 15, 2002)
+=======================================================================
+
+1.     Fixed behaviour of dump when exceeding resource limits
+       (SIGXFSZ treatment).
+
+2.     Added the -L flag to restore to allow the user to specify a 
+       maximal allowed number of miscompares when using restore
+       with the -C option to check the backup.
+
+3.     Detailed the manual entry for the -N option of restore.
+
+4.     Added the -a flag to restore to make able doing unattended
+       restores in -i or -x mode (automatically walks through the
+       multiple dump volumes).
+
+5.     Extended the QFA mode to work with local files and/or
+       remote tapes and files. This way, restore can know in advance
+       the tape number and the offset for the inodes to extract and 
+       can minimize the extraction time by seeking directly to the 
+       good tape/offset.
+
+6.     Added the -A <archive> option to both dump and restore, 
+       which makes dump to archive a dump table-of-contents in
+       the specified file to be used by restore to determine
+       whether a file is in the dump file that is being restored.
+       (the archive file syntax is also compatible with the
+       Solaris ufsdump generated one).
+
+7.     Small fix in restore making it able to read some (broken ?)
+       Solaris ufsdump tapes.
+
+8.     Fixed dump to correctly recognise the root filesystem when using
+       ext2 disk labels (LABEL=/). Thanks to John Yu <jky@it.bu.edu>
+       for reporting this bug.
+
+9.     Added the -P <file> option to restore to create a
+       Quick File Access file from an already made dump. Patch 
+       contributed by Uwe Gohlke <uwe@ugsoft.de>.
+
+10.    Made restore compile and run on Solaris, making it a 
+       possible replacement for the standard ufsrestore. Port was
+       contributed by Uwe Gohlke <uwe@ugsoft.de>.
+
+Changes between versions 0.4b25 and 0.4b26 (released January 7, 2002)
+=====================================================================
+
+1.     Added a set of backup scripts from Eugenio Diaz
+       <getnito@yahoo.com> in the examples section. It features
+       automatic (cron based) full and incremental dumping of
+       several filesystems on a separate filesystem.
+
+2.     Fixed a off-by-one miscalculation which disabled dumping
+       a one letter subdirectory. Thanks to Chris Siebenmann 
+       <cks@utcc.utoronto.ca> for reporting the bug.
+
+3.     Fixed several restore bugs occuring when trying to
+       restore some missing files on the tape. Thanks to Chris
+       Siebenmann <cks@utcc.utoronto.ca> for reporting the bug.
+
+4.     Fixed --with-ldopts configure argument passing, installing from
+       a separate object directory, makefile cleanups contributed
+       by <splite@purdue.edu>.
+
+5.     Fix a bug which could caused, in some conditions, the highest
+       number inode of a filesystem, to not be dumped. Many thanks
+       to Chris Siebenmann <cks@utcc.utoronto.ca> for helping me
+       chase this bug.
+       
+Changes between versions 0.4b24 and 0.4b25 (released November 17, 2001)
+=======================================================================
+
+1.     Added a mini howto from Patrick Walsh in the examples 
+       directory.
+
+2.     Minor man pages syntax corrections. Thanks to
+       Chris Danis <screechco@home.com> for reporting the bugs.
+
+3.     Added a script from David B. Peterson <dave@toppledwagon.com>
+       to the examples section. It features dumping several
+       filesystems to a remote tape drive upon ssh.
+
+4.     Added a patch provided by Richard Jones <rich@annexia.org>
+       which allows BRADEMAX (number of read errors tolerated by
+       dump) to be adjusted using the -I option.
+
+5.     Fixed a bug which disabled doing "restore -C -f -". Thanks
+        to Clemens Stiglechner <a9401816@unet.univie.ac.at> for the
+       patch.
+
+6.     Add the -l option to restore to specify if, when doing a
+        remote restore, the file used to access the backup is a
+       regular file (the defaults being a tape drive). Restore needs
+       to know this information when reading a remote compressed 
+       dump. Previously, this information was autodetected, but
+       the autodetection code fails (with ioctl: Inappropriate ioctl 
+       for device) when using a non Linux remote box. Thanks to 
+       many users and especially to Eros Albertazzi 
+       <eros@lamel.bo.cnr.it> for reporting this.
+
+7.     Found a workaroung for the dump deadlock problem (3 childs 
+       stuck in pause(), father in read()). The workaround seems
+       to work for me and several beta-testers. If it doesn't work
+       for you, please report back.
+
+8.     Updated the RPM spec file (BuildPrereq, URL etc).
+
+Changes between versions 0.4b23 and 0.4b24 (released September 12, 2001)
+========================================================================
+
+1.     Fixed the permissions of a newly created QFA file by dump.
+
+2.     Cleaned up the source of dump (the external variables 
+       definition was a complete mess, making possible to have
+       objects overlap).
+
+3.     Fixed restore to use the full tape volume path when doing
+       a compare (since it changes the working directory to the
+       filesystem being compared in the process).
+
+4.     Added the -q option to dump which makes dump abort 
+       whenever it needs operator attention. It should be
+       easier to use dump in scripts with this option.
+
+5.     Detect the use of incompatible options to dump and
+       refuse them (like -a and -B options together).
+
+6.     Added bzip2 compression to dump/restore (use option -j level 
+       to select it). Note that you will need a restore version
+       >= 0.4b24 in order to restore a bzip2 compressed dump.
+       The same warning as for the zlib compression applies:
+       the tape format of a bzip2 dump is not compatible with the
+       original BSD tape format.
+
+7.     Fixed a overflow problem in dump corrupting the dump when
+       very large files were encountered. Thanks to Vladimir Nadvornik 
+       for the bug report.
+
+8.     Added a ioctl(BLKFLSBUF) in dump which should flush the
+       kernel buffer/page cache before starting the dump, helping
+       a bit those who use dump on mounted filesystems. Thanks to
+       John Yu <jky@it.bu.edu> and to Theodore T'so <tytso@mit.edu>
+       for this suggestion.
+
+9.     Updated the RPM spec file following the RedHat changes 
+       (dynamically linked binaries now in /usr/sbin etc).
+
+10.    Added a patch from Helmut Jarausch <jarausch@igpm.rwth-aachen.de>
+       which enables restore to recognise multi volume compressed dumps
+       done on CD. Included his scripts for dump (which pipe the dump
+       output directly into cdrecord) and restore. There is now 
+       possible to to backups to CD on the fly!
+
+Changes between versions 0.4b22 and 0.4b23 (released July 20, 2001)
+===================================================================
+
+1.     Fixed a buffer overflow in restore/tape.c. Patch provided by
+       Marcus Meissner (Caldera International Security Dept.).
+
+2.     Implement the Sun rmt extended protocol. Patch submitted
+       by Ian Gordon <iangordon@users.sourceforge.net>.
+
+3.     Check for the e2fsprogs header <ext2fs/ext2_fs.h> instead of 
+       the linux kernel header. This ensures that dump always has the
+       latest version of this file. Patch submitted by
+       Andreas Dilger <adilger@turbolinux.com>.
+
+4.     Report any filesystem present in either /etc/fstab with a 
+       positive passno or /etc/dumpdates in dump -w output.
+       Patch submitted by Andreas Dilger <adilger@turbolinux.com>.
+
+5.     Fixed the looping problem in dump introduced in the 
+       previous version.
+
+6.     Changed the -B option of dump to limit the size of 
+       _compressed_ output per volume if compression is on.
+       Patch contributed by Helmut Jarausch 
+       <jarausch@igpm.rwth-aachen.de>. Note however that, since
+       it is impossible to predict the size of the compressed
+       data before doing the compression, the -B limit is a bit
+       conservative.
+
+7.     Fixed a bug in reading the operator typed file/tape path for
+       the next volume in restore.
+
+8.     Implemented a "-F script" option to restore which permits the
+       user to specify a script which will be launched at the
+       beginning of each tape, useful for automatic programming of
+       tape changers for example. See the restore man page for the
+       script parameters and return codes.
+
+9.     Small fix for the QFA routines provided by Uwe Gohlke 
+       <uwe@ugsoft.de>, and some recommendations for QFA uses in
+       the man pages.
+
+10.    Fixed the multivolume restoring where making a mistake
+       to the 'Mount next tape' prompt caused several blocks to
+       be lost.
+
+11.    Enhanced the -e option of dump to take as a parameter a
+       comma separated list of inode numbers.
+
+12.    Added the -E option to dump which specify a file containing
+       inode numbers to exclude from the dump.
+
+13.    Fixed the compressed multi-volume dump + restore.
+
+Changes between versions 0.4b21 and 0.4b22 (released May 12, 2001)
+==================================================================
+
+1.     Made dump report the number of blocks dumped per volume.
+       Thanks to Kenneth Porter <shiva@well.com> for the suggestion.
+
+2.     Fix a bug in dump where waiting too much at the 'change volumes'
+       question caused the volume to be rewritten. Thanks to
+       Graham Reed <greed@users.sourceforge.net> for reporting the
+       bug and providing a patch.
+
+3.     Added a compression option to dump, contributed by Jerry
+       Peters <gapeters@worldnet.att.net>.
+
+       WARNING: the compression works only on files/pipes and 
+       drives supporting variable block size.
+
+       WARNING2: tapes created using the compression feature are
+       incompatible with the standard dump tape format, and a
+       version of restore >= 0.4b22 will be needed for extraction.
+
+4.     Fixed some compilation problems for glibc 2.2.2 and 64 bit 
+       architectures. Thanks to Paul Slootman <paul@debian.org> for
+       the patch and to Bdale Garbee <bdale@gag.com> for forwarding
+       it upstream.
+
+5.     Many cleanups (CPP defines, const char warnings, check of
+       ext2fs COMPAT flags, time_t cleanups, added libext2 version
+       in dump usage text) by Andreas Dilger <adilger@turbolinux.com>.
+
+6.     Made --prefix option work in configure. All the install path
+       are now based on the configure parameters.
+
+7.     Added the Quick File Access mode in dump/restore, contributed
+       by Uwe Gohlke <uwe@ugsoft.de>. In this mode, dump stores in
+       a file tape position for each inode, and this file is used by 
+       restore (if called with parameter Q and the filename)
+       to directly position the tape at the file restore is currently 
+       working on.  This saves hours when restoring single files from
+       large backups, saves the tapes and the drive's head. Use
+       --enable-qfa option of configure to compile in the QFA support.
+
+8.     Added the possibility to dump several files and directories
+       in a single invocation of dump. Thanks to Uwe Gohlke 
+       <uwe@ugsoft.de> for implementing this option.
+
+9.     Fixed the dumping and restoring of files with holes
+       (files ending with holes didn't get dumped or restored 
+       correctly).
+
+10.    Fixed a socket descriptor leak in dump, which leaved opened
+       3 file descriptors per dump process (and there is one dump
+       process per tape).
+
+11.    Fixed dump large file system support, by explicit use of
+       open64/lseek64/etc functions (explicit use needed because 
+       e2fsprogs libraries don't behave well when compiled with 
+       FILE_OFFSET_BITS=64).
+
+Changes between versions 0.4b20 and 0.4b21 (released January 13, 2001)
+======================================================================
+
+1.     Fixed some bugs in the dump -w|-W logic introduced by
+       the previous version. Thanks to Andreas Dilger 
+       <adilger@turbolinux.com> for his help on this one.
+
+2.     Fixed again a compilation problem when using old e2fs
+       headers (filesystem label related). Thanks to many users
+       who reported this stupid error.
+
+3.     Fixed a build problem on old lib5 based systems dealing with 
+       _PATH_MNTTAB being undefined. Thanks to John Adams
+       <johna@onevista.com> for reporting the bug.
+
+4.     Improved the error detection in restore when creating
+       the temporary files in TMPDIR. Now restore will corectly
+       report a 'no space left on device' error instead of 
+       strange errors which could imply an archive corruption.
+       Thanks to Gabriel Somlo <somlo@cs.colostate.edu> and
+       bgjenero <bgjenero@sympatico.ca> for reporting the bug.
+
+5.     Added the throughput information in dump's progression
+       messages.  Thanks to Andreas Dilger <adilger@turbolinux.com> 
+       for the patch.
+
+6.     Use libext2fs's inode scanning routines, which are particularly
+       robust when dealing with errors (especially when having some
+       bad blocks on the filesystem). Many thanks to Colin
+       <colin@horizon.com> for reporting the bug, investigating
+       the issues, finding a workaround, writing the patch and
+       fully testing it... (of course, if this patch will break
+       anything, he is to blame for :-)).
+
+7.     Made dump and restore LFS aware. Dump can dump a filesystem
+       containing large files, generate a large file on output and
+       restore can restore them. This feature is not enabled by
+       default, use --enable-largefile option of configure to enable
+       it (you need to have a LFS aware glibc though). Thanks to
+       Andrea Arcangeli <andrea@suse.de> for submitting the patch,
+       and to Theodore T'so <tytso@valinux.com> for his always
+       useful thoughts.
+
+8.     Made dump ask upon a tape write error if it should rewrite
+       the current volume (assume this is a bad tape) or if it should
+       assume an end-of-tape condition (useful for tape drives which
+       behaves badly at the end of the tape). Thanks to Andreas
+       Dilger <adilger@turbolinux.com> for the suggestion.
+
+Changes between versions 0.4b19 and 0.4b20 (released November 10, 2000)
+=======================================================================
+
+1.     Fixed a small compilation problem due to a change
+       in the definintion of the struct sigaction in
+       glibc 2.0 / libc5. Thanks to Gunther Schlegel 
+       <schlegel@riege.de> for reporting the bug and to
+       Dave Platt <dplatt@snulbug.mtview.ca.us> for suggesting
+       a fix.
+
+2.     Modified the label and uuid analysis in order to be 
+       self-contained (independant of kernel/libc headers). This 
+        should fix the compile with older kernel/libc headers and
+       will preserve the functionality. Thanks to Bernhard Erdmann
+       <bernhard.erdmann@gmx.de> for reporting the bug.
+
+3.     The 'exclude inode' option, if applied to a directory
+       inode, excludes now correctly all the leaves of this 
+       directory. Thanks to John R. Dennison 
+       <gerdesas@users.sourceforge.net> for reporting the bug.
+
+4.     Fixed the '-e' option to disable the possibility
+       to exclude the root inode (which causes the dumps to
+       be unreadable by restore). Prevented array overflow
+       when multiple -e options are used.
+
+5.     Fixed dump to correctly interpret a filesystem argument
+       which is a mountpoint and it is not an absolute path 
+       (as specified in the fstab). Thanks to Bernhard R. Erdmann 
+       <be@berdmann.de> for reporting the bug.
+
+6.     Made dump able to backup files larger than 2 GB. Note that
+       dump still doesn't cope with files larger than 4 GB.
+
+7.     Restore the real uid and gid before invoking an external
+       RSH program (big hole when dump or restore is suid root!).
+
+8.     Get the values for the default tape device and the location
+       of fstab file from the system headers. Thanks to
+       Andreas Dilger <adilger@turbolinux.com> for the patch.
+
+9.     Made dump -w|-W report all recognized filesystems 
+       present in either /etc/fstab or /etc/dumpdates, and present
+       the list in the same order as in fstab file. Thanks
+       to Andreas Dilger <adilger@turbolinux.com> for the patch.
+
+10.    Made dump's -a (automatic end of tape detection) the
+       default. Specifying one of -B, -c, -d or -s options will
+       override the EOM detection. Thanks to Andreas Dilger
+       <adilger@turbolinux.com> for the patch.
+
+11.    Save the ext2 filesystem label into the dump volume label.
+       Specifying a volume label on the command line (-L option)
+       will override this feature. Thanks to Andreas Dilger
+       <adilger@turbolinux.com> for the patch.
+
+Changes between versions 0.4b18 and 0.4b19 (released August 20, 2000)
+=====================================================================
+
+1.     Fixed the signal handling in dump (which I broke in 0.4b17)
+       which was causing several strange dump failures (dump
+       hanged or segmentation faults etc). 
+
+2.     Specified the default blocksize in the dump man page.
+
+3.     Changed two info messages of restore to be written on stdout
+       instead of stderr in order to leave stderr only for errors
+       or warnings. Thanks to Stephen Atwell 
+       <satwell@urbana.css.mot.com> for the suggestion.
+
+4.     Corrected an off by one calculation which prevented
+       dumping a directory having a 1 character name length.
+       Thanks to Bernhard Erdmann <bernhard.erdmann@gmx.de>
+       for reporting the bug.
+
+5.     Reinforce dump in order to allow only level 0 and no
+       -u option when dumping a subdirectory, and document 
+       this in the man page. Thanks to Bernhard Erdmann 
+       <bernhard.erdmann@gmx.de> for reporting the bug.
+
+6.     Fixed a small harmless bug in restore which caused
+       in some conditions hard links to be restored several
+       times (therefore generation some warning messages).
+       Thanks to Kenneth Porter <shiva@well.com> for
+       reporting the bug.
+
+7.     Updated the RPM spec file to the latest RedHat version,
+       providing FHS packaging and other cosmetic changes.
+       You will need RPM version >= 3.0.5 in order to build the RPM.
+
+8.     Updated the configure script to check for libtermcap
+       before checking for libreadline, because we need this
+       library in order to compile the readline support.
+
+9.     Made dump understand the LABEL= and UUID= notation
+       both in /etc/fstab and on the command line. Note that
+       you will need the /proc filesystem in order to use
+       these notations. Thanks to Erik Troan <ewt@redhat.com> 
+       for providing the patch.
+
+Changes between versions 0.4b17 and 0.4b18 (released June 30, 2000)
+===================================================================
+
+1.     Fixed a potential buffer overflow in restore. Thanks
+       to Stan Bubrouski <satan@fastdial.net> for reporting 
+       the bug.
+
+2.     Fixed a readline-related bug which prevented
+       'cat DUMPFILE | restore -i -f -' from working. Thanks
+       to Charles Karney <karney@users.sourceforge.net>
+       for the bug report.
+
+3.     Changed a few "panic" into "exit", causing restore to
+       be more stable against some attacks (like the last one
+       reported on Bugtraq, although the last version of restore
+       was not vulnerable - just dumped core). Thanks to
+       Andreas Hasenack <andreas@conectiva.com.br> for reporting
+       the bugs to me.
+
+4.     Removed the suid-root bit on dump and restore in the
+       default build (and generated RPMs). It should be safer
+       now. Users who need the suid-root capabilities in order
+       to make network backups should read first the man page
+       of dump and enable the suid bit manually.
+
+5.     Added -ltermcap to the compile parameters for restore
+       when using readline support, in order to make the compile
+       process work on some systems (SuSE ?). Thanks to 
+       Patrik Schindler <poc@pocnet.net> for reporting the bug.
+
+Changes between versions 0.4b16 and 0.4b17 (released June 1st, 2000)
+====================================================================
+
+1.     The -F script is called now *only* at the end of a tape,
+       not at the end of the dump. Thanks to Christian Haul
+       <haul@informatik.tu-darmstadt.de> for the bug report.
+
+       Normally, the device name and the current volume number
+       are passed on the command line of the script. However,
+       if you want the old style script (with no arguments
+       passed on the command line), you can enable it in
+       configure with the --enable-oldstylefscript.
+
+2.     Use posix signal handling to preserve dump functionality 
+       with libc5. Thanks to Jeff Johnson <jbj@redhat.com> for
+       the patch.
+
+3.     Made the exit code of restore in case of a 'C'ompare
+       command reflect the result of the compare. An exit status
+       of 0 means the dump archive is correct, 1 means tape errors,
+       2 means that some files were modified. Thanks to Kenneth Porter
+       <shiva@well.com> for the suggestion.
+
+4.     Made (finally) quotes work in interactive restore.
+
+5.     Small fixes in order to allow dump to compile with a 
+       really old e2fsprogs version. Thanks to Ian Zimmerman 
+       <itz@speakeasy.org> for the bug report.
+
+6.     Add GNU readline capabilities to interactive restore.
+       Use configure's --enable-readline flag to enable this feature.
+       Thanks to Patrik Schindler <poc@pocnet.net> for the
+       suggestion.
+
+7.     Do the compare on the fly in restore 'C' mode (this will
+       allow not to exhaust the available /tmp space when 
+       ccmparing large files). Thanks to Kenneth Porter
+       <shiva@well.com> for the suggestion.
+
+Changes between versions 0.4b15 and 0.4b16 (released March 11, 2000)
+====================================================================
+
+1.     Fixed some several duplicate 'DUMP: DUMP:' in the
+       output of dump.
+
+2.     Corrected the estimation of blocks to dump. Note that
+       this is still wrong for large directory inodes, due
+       to the size of a BSD directory entry on the tape
+       (estimation is based on the size of the ext2 directory,
+       which is smaller because it doesn't contain the null
+       character at the end).
+
+3.     Made dump report the total number of MB written to
+       tape at the end of run. Thanks to W. Reilly Cooley
+       <wcooley@nakedape.cc> for the patch.
+
+4.     Added the -X option to restore giving the possibility
+       to read the names of the files to be extracted/listed 
+       from a text file (in addition of the command line). 
+       Thanks to Dejan Muhamedagic <dejan@quant-x.com> for the 
+       patch.
+
+5.     Added the device name and the current volume number
+       as arguments to the end of tape script (dump -F option).
+
+6.     Made the multi-volume dump work again (after having 
+       broken it in 0.4b15). 
+
+Changes between versions 0.4b14 and 0.4b15 (released March 2, 2000)
+===================================================================
+
+1.     Added a prompt command in interactive restore mode. Thanks
+       to Andreas Dilger <adilger@home.com> for the patch.
+
+2.     Fixed a buffer overflow problem in dump (caused by 
+       not checking the size of the filesystem parameter). 
+       Thanks to Kim Yong-jun <loveyou@hackerslab.org> for
+       reporting this on Bugtraq (and to several dump users
+       who forwarded me his mail).
+
+3.     Added the '-F script' option to dump in order to 
+       launch a script at the end of each tape (to be used
+       with a tape changer, or to notify the sysadmin by
+       pager etc.).
+
+4.     Fixed a bug in restore compare code caused by the changes 
+       I made in 0.4b14.
+
+5.     Fixed the treatment of options using the old BSD syntax
+       in both dump and restore.
+
+Changes between versions 0.4b13 and 0.4b14 (released February 10, 2000)
+=======================================================================
+
+1.     Fixed a bug in dump which may have caused invalid deleted 
+       directories to be dumped out if they were deleted after the
+       mapping pass. This could occure on active filesystem and lead
+       to heap corruption (causing dump malfunction in many possible ways).
+       Thanks to Jan Sanislo <oystr@cs.washington.edu> for finding this
+       bug and submitting the patch.
+
+2.     Fixed the handling of the filesystem parameter in dump. A
+       '/mnt/disk' parameter caused the disk contents to be dumped,
+       but a '/mnt/disk/' parameter caused the mountpoint directory
+       to be dumped (generally an empty directory).
+
+3.     Improved the output of dump in order to tell which directory
+       it is currently dumping (when dumping a subtree).
+
+4.     Added the '-e' exclude inode option to dump. Thanks to
+       Isaac Chuang <ike@isl.stanford.edu> for contributing with the patch.
+
+5.     Added a REPORTING-BUGS file in order to provide a guide
+       on how to correctly report a bug in dump/restore.
+
+6.     Fixed a restore problem when restoring a hard link to an inode
+       having the immutable or append-only attribute set. Thanks to
+       Ambrose Li <acli@mingpaoxpress.com> for submitting the patch.
+
+7.     Fixed a compatibility problem between dumps made on little
+       endian machines (the format was correct) and big endian 
+       machines (the format was incorrect). This fix break the
+       compatibility with the older dumps made on big endian 
+       machines (sparc, m86k, ppc etc). For the first time in
+       linux dump's history (I believe), the dumps made by *BSD, 
+       Linux/alpha, Linux/sparc and Linux/x86 are compatible, 
+       so interchangeable. Thanks to Rob Cermak
+       <cermak@ahab.rutgers.edu> for submitting the bug and
+       helping me test the fix.
+
+8.     Fixed the way dump reports the remaining percent/time, if
+       the number of blocks actually dumped exceeds the estimated
+       number of blocks. Thanks to Jean-Paul van der Jagt 
+       <jeanpaul@dutepp0.et.tudelft.nl> for reporting the bug.
+
+Changes between versions 0.4b12 and 0.4b13 (released January 21, 2000)
+======================================================================
+
+1.     Small Y2K fix in the man pages :). Thanks to Bernhard Sadlowski
+       <sadlowsk@Mathematik.Uni-Bielefeld.DE> for reporting the bug.
+
+2.     Removed the requirement to build the RPM as root from the
+       spec file. Thanks to Christian Weisgerber 
+       <naddy@mips.rhein-neckar.de> for submitting this.
+
+3.     Fixed a bug in dump related to the 'filetype' feature of ext2fs,
+       causing dump to block when dumping really huge filesystems.
+       Many thanks to Patrik Schindler <poc@pocnet.net> for 
+       helping me find this bug.
+
+4.     Fixed the treatment for an interrupt signal when dump access
+       the remote tape through RSH. Thanks to Christian Weisgerber
+       <naddy@mips.rhein-neckar.de> for providing the patch.
+
+5.     Fixed a bug which was causing dump/restore to display
+       garbage characters instead of the remote host name.
+
+Changes between versions 0.4b11 and 0.4b12 (released January 8, 2000)
+=====================================================================
+
+1.     Small fix in the dump man page. Thanks to Thorsten Kukuk 
+       <kukuk@suse.de> for submitting the patch.
+
+2.     Fix for the exit code when using the size estimate option of
+       dump. Thanks to Matti Taskinen <mkt@rni.helsinki.fi> for
+       submitting the patch.
+
+3.     Handle EINTR in atomical reads/writes in dump, which was causing
+       dump to fail on some systems. Thanks to Eric Jergensen
+       <eric@dvns.com> for reporting the bug and submitting the patch.
+
+4.     Handle more than 16 characters for the device names in dumpdates.
+       (up to 255 now). Thanks to Rainer Clasen <bj@ncc.cicely.de> for
+       tracking down the problem and proposing the solution.
+
+5.     Fixed a bug in dump which prevented the creation of the
+       dumpdates file when doing a 0-level dump without already
+       having a dumpdates file. Thanks to Patrik Schindler 
+       <poc@pocnet.net> for reporting the bug.
+
+6.     Changed the way dump 'S' flag reports the size estimate
+       from number of blocks into bytes (making it compatible
+       with the Solaris version, and simplifying things for
+       amanda users). Thanks to Jason L Tibbitts III 
+       <tibbs@math.uh.edu> for reporting the bug.
+
+7.     Fixed a compatibility problem in linux/alpha dump tape format.
+       Now the linux/alpha dump are (again) compatible with the
+       other dump formats. But this breaks compatibility with
+       older dumps made on alpha. Thanks to Mike Tibor 
+       <tibor@lib.uaa.alaska.edu> for helping me in finding this bug.  
+
+Changes between versions 0.4b10 and 0.4b11 (released December 5, 1999)
+======================================================================
+
+1.     Added a '--enable-kerberos' to configure.
+
+2.     Added a 'S' option to dump which determines the amount of space
+       that is needed to perform the dump without actually doing it, similar
+       to the Sun's ufsdump 'S' option. Patch contributed by Rob Cermak
+       <cermak@ahab.rutgers.edu>.
+
+3.     Added a 'M' multi-volume option to dump and restore which enables
+       dumping to multiple files (useful when dumping to an ext2
+       partition to make several dump files in order to bypass the 2GB
+       file size limitation). The 'f' argument is treated as a prefix and
+       the output files will be named <prefix>001, <prefix>002 etc. With
+       the 'M' flag, restore automatically selects the right file without
+       asking to enter a new tape each time.
+
+4.     Fixed a memory leak which was causing dump to grow very big
+       (270MB when dumping a 10GB filesystem...). Thanks to Jason 
+       Fearon <jasonf@netrider.org.au> for reporting the bug.
+
+Changes between versions 0.4b9 and 0.4b10 (released November 21, 1999)
+======================================================================
+
+1.     Make configure test if the system glob routines support 
+       extended syntax (ALTDIRFUNC). If not, use the internal glob
+       routines instead of system ones. Thanks to Bernhard Sadlowski 
+       <sadlowsk@Mathematik.Uni-Bielefeld.DE> for reporting the bug
+       and helping me resolve this and other minor libc5 compiling
+       glitches.
+
+2.     Fix a problem when dumping a ext2fs with the 'filetype'
+       feature enabled. Thanks to Patrick J. LoPresti 
+       <patl@cag.lcs.mit.edu> for reporting the bug and to
+       Theodore Y. Ts'o <tytso@mit.edu> for providing the patch.
+
+3.     Made the nodump flag work on directories. A directory which
+       has the nodump flag gets never dumped, regardless of its
+       contents.
+
+4.     Integrate a patch from Jeremy Fitzhardinge <jeremy@goop.org>
+       which allows dump on an active ext3 filesystem. However, this
+       is a "quick and dirty" patch which enables backup of an ext3
+       filesystem through the ext2 compatibility (by ignoring the
+       NEEDS_RECOVERY bit). The journal file is not recognized and
+       it is dumped (it should not). 
+
+5.     Test the superblock compatibility flags when dumping, in order
+       to be sure that we know how to deal with specific features.
+
+Changes between versions 0.4b8 and 0.4b9 (released November 5, 1999)
+====================================================================
+
+1.     Use lchown instead of chown, fixing a possible security problem 
+       when restoring symlinks (a malicious user could use this
+       to deliberately corrupt the ownership of important system files).
+       Thanks to Chris Siebenmann <cks@utcc.utoronto.ca> for detecting
+       this and providing the patch.
+
+Changes between versions 0.4b7 and 0.4b8 (released November 3, 1999)
+====================================================================
+
+1.     Put dump sources under CVS, added Id tags in all files so
+       one can use 'ident' on binary files.
+
+2.     Added the dump/restore version in the usage text so one can
+       easily verify the version he is using.
+
+3.     Small patch from Nuno Oliveira <nuno@eq.uc.pt> which fixes
+       a va_start/va_end problem on linux-ppc (always call va_start
+       va_end in pairs each time we use a vararg function).
+
+4.     Added again the DT_* constants because old libc does not
+       contain them :(. Thanks to Eric Maisonobe <virnet@nat.fr>
+       for submitting the bug report.
+
+5.     Use ext2fs_llseek instead of llseek. With recent e2fsprogs
+       this should enable dumping big (huge) filesystems.
+
+6.     Added the RSH environment variable in order to be able to
+       use a rsh replacement like ssh when doing remote backups (and
+       bypass the security limitations of rcmd). Now you can do remote
+       backups without being root (or making dump setuid root).
+
+7.     Modified again the way dumpdates works. For incremental dumps,
+       we need to read dumpdates even if we are not using 'u' option.
+       Thanks to Bdale Garbee <bdale@gag.com> for his ideas on how
+       this should work.
+
+Changes between versions 0.4b6 and 0.4b7 (released October 8, 1999)
+===================================================================
+
+1.     Removed the 'k' flag from the restore 'about' text if kerberos
+       was not compiled in.
+
+2.     Prototyped (f)setflags from e2fsprogs and corrected the calls
+       to them (fsetflags takes a char*, setflags an open fd!).
+
+3.     (f)setflags is called only if the flags aren't empty. If the
+       file is a special file, a warning is printed, because changing
+       flags implies opening the device. Normally, a special file
+       should not have any flag... (Debian bug #29775, patch provided
+       by Abhijit Dasgupta <abhijit@ans.net>).
+
+4.     Made possible to dump a file system not mentioned in /etc/fstab.
+       (Debian bug #11904, patch provided by Eirik Fuller <eirik@netcom.com>).
+
+5.     Changed the default behaviour to not create dumpdates
+       unless 'u' option is specified. Removed the old "debian-patch"
+       which provided the same thing. (Debian bug #38136, #33818).
+
+6.     Removed all those dump*announce, since they were getting old...
+
+7.     Added warning messages if dumpdates does not exist and
+       when an inferior level dump does not exist (except for a level 0
+       dump).
+
+8.     Debugged the glob calls in interactive mode: restore used a 
+       dirent struct which was different from the /usr/include/dirent.h
+       one (this used to work, is it a glibc2 change?), so none of the 
+       compat glob (which used /usr/include/dirent.h) or the system glob 
+       worked. Restore use now the system dirent (and the system 
+       DT_* constants), which are compatible with BSD ones.
+
+9.     Added a configure flag (--with-dumpdatespath) to specify
+       the location of dumpdates file. By default, it is 
+       /etc/dumpdates.
+
+10.    Added the "AUTHOR" and "AVAILABILITY" sections and 
+       included the current date/version in man pages.
+
+11.    Corrected the estimation of remaining time when
+       the operator doesn't change the tapes quickly enough. This
+       was an old bug, I thought I corrected it, and discovered
+       that in fact it was corrected in two different places, so
+       the results canceled each other...
+
+Changes between versions 0.4b5 and 0.4b6 (released October 1, 1999)
+===================================================================
+
+1.     Integrated multiple patches from RedHat, Debian and SuSE:
+
+       - tweak dump/itime.c to not try to read dumpdates if the 'u' option 
+         isn't specified.
+       - several fixes in the man pages.
+       - update the default tape device to /dev/st0.
+       - many updates for Linux Alpha (byte ordering, size_t etc).
+       - buffer overruns.
+       - use environment variable for TMPDIR (instead of /tmp).
+       - use sigjmp_buf instead of jmp_buf (RedHat bug #3260).
+       - workaround egcs bug (RedHat bugs #4281 and #2989).
+       - wire $(OPT) throughout Makefile's.
+
+2.     Upgrade the dump revision to 1, making possible to dump filesystems
+       made with e2fsprogs-1.15 or newer. Nothing seems to break...
+
+3.     Fix some compile warnings, prototype all functions.
+
+4.     Use glibc err/glob instead of internal compatibility
+       routines (only if available).
+
+5.     Fix a compile error on Linux 2.2.7 / libc5 (5.4.44) (patch provided
+       by Bernhard Sadlowski <sadlowsk@mathematik.uni-bielefeld.de>).
+
+Changes between versions 0.4b4 and 0.4b5 (released September 22, 1999)
+======================================================================
+
+1.     Integrated the changes from FreeBSD-3.1-RELEASE
+       (mostly bug fixes, buffer overruns, dump has now an "automatic
+       tape length calculation" flag, dump/restore can use kerberos now
+       (this is NOT tested), use environment variables for TAPE and
+       RMT etc.).
+
+2.     Integrated three RedHat patches ("glibc", "kernel" and "bread" patches)
+
+3.     Corrected a bug in restore when using 'C' option with multi-volumes
+       tapes (files splited accros two tapes give "size changed" errors
+       when comparing).
+
+4.     Corrected the long standing bug when dumping multiple tapes.
+       This works for me, needs further testing.
+
+Changes between versions 0.4b3 and 0.4b4 (released January 17, 1997)
+====================================================================
+
+1.     Dump now runs correctly on kernels 2.1.x
+       Fix made by Gerald Peters <gapeters@worldnet.att.net>
+
+Changes between versions 0.4b2 and 0.4b3
+========================================
+
+1.     Use realpath() if available
+
+2.     Report statistics
+
+Changes between versions 0.4b1 and 0.4b2
+========================================
+
+1.     Fixed the bug fix from Greg Lutz (I had made a mistake when integrating
+       the patch)
+
+2.     Fixed restore to make it able to read FreeBSD 2.x dumps again
+
+3.     Fixed configure.in to correctly handle --enable-rmt
+
+Changes between versions 0.3 and 0.4b1
+======================================
+
+1.     Integrated the changes from 4.4BSD-Lite2
+
+2.     Integrated the patches from Debian and Red Hat
+
+3.     Portability changes: use the __u32, __u16, __s32, and __s16 types
+
+4.     Changed dump to use the Ext2fs library to get block addresses.  This
+       should solve the endianness problem on SparcLinux.
+
+5.     Created a configure.in file (shamelessly stolen from the e2fsprogs
+       distribution's one) to use autoconf
+
+6.     Fixed a few minor bugs
+
+Changes between versions 0.2e and 0.2f
+======================================
+
+1.     Added the creation of named pipes (fifos) in restore.
+
+2.     Added the -N flag in the restore manual page.
+
+3.     Added the file kernel.patch which contains the llseek() optimization
+       patch for 1.2.x kernels.
+
+4.     Fixed a bug in the restoration of symbolic links: owner and group were
+       not restored.
+
+5.     Integrated some changes from FreeBSD 2.2.
+
+6.     Added a call to ftruncate() after restoring each file to restore
+       correctly files ending by a hole.
+
+Changes between versions 0.2d and 0.2e
+======================================
+
+1.     Fixed a bug in the "set owner/mode" process.  Every file was restored
+       with owner = root (0) and group = root/wheel/whatever (0).
+
+Changes between versions 0.2c and 0.2d
+======================================
+
+1.     Dump is now able to backup 2GB+ filesystems.
+
+2.     Dump and restore can now be linked as static binaries.
+
+Changes between versions 0.2b and 0.2c
+======================================
+
+1.     Fixed a bug when dumping ``slow'' (i.e. normal) symbolic links.
+
+Changes between versions 0.2a and 0.2b
+======================================
+
+1.     Really fixed the bug that I should have corrected in 0.2a.
+
+2.     Enabled optimization again.
+
+Changes between versions 0.2 and 0.2a
+=====================================
+
+1.     Disabled the optimization during compilation.
+
+Changes between versions 0.1 and 0.2
+====================================
+
+1.     Fixed a bug in fstab.c which caused a null pointer to be stored in
+       the fs_type field (actually, I modified the file fstab.c to make it
+       use the mntent functions).
+
+2.     Dump and restore now use a 4.3 BSD compatible dump format.  Backups
+       made by dump should be readable by the BSD restore and backups made
+       by the BSD dump should be readable by restore.  Unfortunately, this
+       means that the dump format has changed between version 0.1 and version
+       0.2 :-(
+
+3.     Dump is now able to backup a subtree, it is no longer limited to whole
+       filesystems like the BSD version.
+
+4.     Dump now uses ext2_llseek() so it is able to backup filesystems bigger
+       than 2 GB.
+
+Changes between versions 0.0 and 0.1
+====================================
+
+1.     Now create links rdump and rrestore during the `make install' step.
+
+2.     Linux port specific bugs added to the manual pages
+
+3.     Incorrect estimation of the number of tapes blocks fixed when doing
+       incremental backups.
+
+4.     Better ls-like format in restore in interactive mode.
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644 (file)
index 0000000..a9db587
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,36 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1980, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..00fdcef
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,17 @@
+$Id: INSTALL,v 1.3 2003/02/11 08:57:41 stelian Exp $
+
+       Installation of the dump/restore port should be quite easy, since
+a configure script is now provided.
+
+       Configuration is made by running the configure script.  Run
+`configure --help' to get a list of options.
+
+       After configuring the package, you can type `make' to compile the
+programs, and `make install' to install the binaries in /usr/local/sbin and
+the manual pages in `/usr/local/man/man8'.
+
+       You need to have the latest Ext2fs programs installed on your system
+since this version of dump uses the Ext2fs library written by Theodore T'so.
+The Ext2fs programs are included in all Linux distributions (e2fsprogs and
+e2fsprogs-dev[el] packages), or you can download the most up to date version
+from http://e2fsprogs.sourceforge.net.
diff --git a/KNOWNBUGS b/KNOWNBUGS
new file mode 100644 (file)
index 0000000..e79ded9
--- /dev/null
+++ b/KNOWNBUGS
@@ -0,0 +1,17 @@
+$Id: KNOWNBUGS,v 1.5 1999/11/21 00:17:12 tiniou Exp $
+
+Known bugs and limitations of the dump/restore port
+===================================================
+
+1.     I have tried to minimize changes in the BSD source and some parts
+       may look ugly.  dump/tape.c is really awfull but this is pure BSD
+       code :-)  Maybe, I should replace it with a simpler and cleaner
+       version.
+
+2.     Kerberos mode is _NOT_ tested.
+
+3.     Some users related possible problems when dumping
+       active (mounted) filesystems. The problems are reported as
+       lseek and read error messages (with a negative count). If
+       you encounter this kind of problems, please report them
+       to the author.
diff --git a/MAINTAINERS b/MAINTAINERS
new file mode 100644 (file)
index 0000000..b66b3e6
--- /dev/null
@@ -0,0 +1,15 @@
+$Id: MAINTAINERS,v 1.4 2002/01/16 09:32:14 stelian Exp $
+
+The dump and restore backup suit was ported to Linux's Second
+Extended File System by Rémy Card <card@Linux.EU.Org>
+
+He was the maintainer of the initial versions of dump (up and
+including 0.4b4, released in january 1997).
+
+I decided to continue the developpement and release a new version.
+Rémy didn't respond to any mail I sent to him, so I have
+promoted myself as the new maintainer :)
+
+So, starting with 0.4b5, the new maintainer is me,
+Stelian Pop <stelian@popies.net>.
+
diff --git a/MCONFIG.in b/MCONFIG.in
new file mode 100644 (file)
index 0000000..e20399e
--- /dev/null
@@ -0,0 +1,99 @@
+VERSION=       0.4b37
+DATE=          July 7, 2004
+
+AR=            @AR@
+CC=            @CC@
+INSTALL=       @INSTALL@
+LD=            @LD@
+LN_S=          @LN_S@
+MV=            @MV@
+RANLIB=                @RANLIB@
+RM=            @RM@
+
+BINOWNER=      @BINOWNER@
+BINGRP=                @BINGRP@
+BINMODE=       @BINMODE@
+MANOWNER=      @MANOWNER@
+MANGRP=                @MANGRP@
+MANMODE=       @MANMODE@
+
+INSTALLBIN=    $(INSTALL) -o $(BINOWNER) -g $(BINGRP) -m $(BINMODE)
+INSTALLMAN=    $(INSTALL) -o $(MANOWNER) -g $(MANGRP) -m $(MANMODE)
+
+prefix=                @prefix@
+exec_prefix=   @exec_prefix@
+SBINDIR=       @sbindir@
+MANDIR=                @mandir@/man8
+
+DUMPDATESPATH= @DUMPDATESPATH@
+#
+# Global include directories
+#
+GINC=          -I$(top_builddir) -I$(top_srcdir)/compat/include
+# indicate where the ext2fs library can be found (this is not needed if you
+# have run `make install-libs' in the e2fsprogs source directory).
+#GINC+=                -I/usr/src/e2fsprogs-0.5c/lib
+
+#
+# Global libraries
+#
+# indicate where the ext2fs library can be found (this is not needed if you
+# have run `make install-libs' in the e2fsprogs source directory).
+#GLIBDIR=      -L/usr/src/e2fsprogs-0.5c/lib
+GLIBS=         $(GLIBDIR) -L../compat/lib -lcompat -lext2fs -lcom_err
+
+#
+# Definitions (don't change them unless you know what you are doing)
+#
+DEFS=          -DRDUMP -DRRESTORE -DLINUX_FORK_BUG -DHAVE_LZO -D_PATH_DUMPDATES=\"$(DUMPDATESPATH)\" -D_DUMP_VERSION=\"$(VERSION)\" @OPTDEFS@  
+
+all::
+
+#
+# Autoconf magic
+#
+
+$(top_builddir)/config.status: $(top_srcdir)/configure
+       (cd $(top_builddir); ./config.status --recheck)
+
+$(top_builddir)/MCONFIG:       $(top_srcdir)/MCONFIG.in \
+                               $(top_builddir)/config.status
+       (cd $(top_builddir); ./config.status)
+
+$(top_builddir)/config.h:      $(top_srcdir)/config.h.in \
+                               $(top_builddir)/config.status
+       (cd $(top_builddir); ./config.status)
+
+Makefile:                      $(srcdir)/Makefile.in $(top_builddir)/MCONFIG \
+                               $(top_builddir)/config.status
+       (cd $(top_builddir); ./config.status)
+
+$(top_srcdir)/configure:       $(top_srcdir)/configure.in
+       cd $(top_srcdir) && autoconf
+
+$(top_srcdir)/config.h.in:     $(top_srcdir)/configure.in
+       cd $(top_srcdir) && autoheader
+
+#
+# Make depend magic
+#
+
+.depend:                       Makefile $(SRCS) $(top_srcdir)/depfix.sed
+       if test -n "$(SRCS)" ; then \
+               $(CC) -M $(CFLAGS) $(SRCS) | \
+                       sed -f $(top_srcdir)/depfix.sed \
+                           -e 's; $(srcdir)/; $$(srcdir)/;g' \
+                           -e 's; $(top_srcdir)/; $$(top_srcdir)/;g' \
+                           -e 's; $(top_builddir)/; $$(top_builddir)/;g' \
+                           -e 's; \./; ;g' \
+                           -e '/^ *\\$$/d' > .depend; \
+       else :; fi
+
+depend::                       .depend
+       if test -n "$(SRCS)" ; then \
+               sed -e '/^# +++ Dependency line eater +++/,$$d' \
+                       < Makefile | cat - .depend \
+                       > Makefile.new; \
+               $(MV) Makefile Makefile.old; \
+               $(MV) Makefile.new Makefile; \
+       else :; fi
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..2dbd90a
--- /dev/null
@@ -0,0 +1,24 @@
+srcdir=                @srcdir@
+top_srcdir=    @top_srcdir@
+top_builddir=  .
+
+@MCONFIG@
+
+RM=            @RM@
+SUBDIRS=       compat/lib compat/include common dump restore @RMTDIR@
+
+all clean install dep depend realclean distclean::
+       for i in $(SUBDIRS); do \
+               (cd $$i && $(MAKE) $@) || exit 1; \
+       done
+
+distclean::
+       $(RM) -f config.status config.log config.cache
+       $(RM) -f MCONFIG Makefile config.h
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..1e96d8d
--- /dev/null
+++ b/README
@@ -0,0 +1,10 @@
+$Id: README,v 1.3 1999/10/11 13:31:04 stelian Exp $
+
+       This is a test release of dump 0.4.
+
+       See the file CHANGES for a list of changes from the previous version.
+
+       See the file INSTALL for installation instructions.
+
+       If you encounter problems with the dump and restore backup suite,
+please contact the maintainers and send them a detailled bug report.
diff --git a/REPORTING-BUGS b/REPORTING-BUGS
new file mode 100644 (file)
index 0000000..479ae42
--- /dev/null
@@ -0,0 +1,57 @@
+Congratulations! You just found a bug in dump/restore and want
+to know what to do next.
+
+Here are some guidelines you will want to follow before sending me
+a mail:
+
+1. Are you sure it's a bug? If you just are not sure about how
+to use a specific feature of dump, please post your question on
+the dump-users mailing list. While you are there, try to browse the
+archives of the mailing list and see if someone asked the same question 
+before.
+
+       NOTE: questions about how to use the d(ensity) (b)locksize parameters
+       enters this category!
+
+2. Always test the last version of dump/restore before submitting a
+bug report. Your problem is maybe already fixed!
+
+3. Consult the bugs using the bug system at sourceforge. Use this 
+bug system if you want to report a new bug or contribute to an
+existing bug. You may want to create an account on sourceforge for that,
+so the comments will automatically be forwarded to your email address.
+
+4. If you are using the bug system and didn't create an account on
+sourceforge, put your email address into the bug report! If I am unable
+to contact you for more information, chances are that the bug will
+never be solved!
+
+5. Please provide detailed information about your system:
+       - distribution and its version (RedHat, Debian, Suse, homemade etc.)
+       - architecture (Intel, Sparc, PalmPilot etc.)
+       - dump/restore version (0.4b13, etc)
+       - e2fsprogs version (1.17, etc)
+       - libc version (libc5, glibc2.0, gilbc2.1 etc)
+       - complete output of the dump/restore command which caused
+         the failure (ok, you can delete the 'xx% done' lines)
+       - the device you dump into/restore from (tape drive, file etc).
+       - anything else you believe will help me to find the bug...
+
+6. In addition, if you want to report a bug on dump, provide also:
+       - details of your filesystem you want to dump: 
+               output of the command 'tune2fs -l /dev/sda1' 
+               (replace sda1 with your partition...)
+       - if your filesystem was mounted when doing the dump, try
+         to rerun the command with the filesystem unmounted. Does
+         the bug still occur?
+       - try to dump your filesystem using /dev/null as tape device. 
+         This may help to know that the bug is not triggered by a
+         buggy device or tape or remote access problems.
+
+
+Ok, here are the pointers you may want to access:
+
+Dump latest release: http://sourceforge.net/project/filelist.php?group_id=1306
+Dump mailing lists: http://sourceforge.net/mail/?group_id=1306
+Dump bug system: http://sourceforge.net/bugs/?group_id=1306
+My email: stelian@popies.net
diff --git a/THANKS b/THANKS
new file mode 100644 (file)
index 0000000..3e2854c
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,134 @@
+$Id: THANKS,v 1.85 2004/07/01 09:14:48 stelian Exp $
+
+Dump and restore were written by the people of the CSRG at the University
+of California, Berkeley.
+
+They were ported to Linux by Remy Card <card@Linux.EU.Org>, by using
+the Ext2fs library, written by Theodore Ts'o <tytso@mit.edu>.
+
+Kevin Layer <layer@Franz.COM> added the comparison code in restore.
+
+Doug Paul <dbp@dragonsys.com> helped me to make dump able to backup 2GB+
+filesystems.
+
+David Frey <david@eos.lugs.ch> (the old Debian dump maintainer), 
+Bdale Garbee <bdale@gag.com> (the new Debian dump maintainer) and the people
+from Red Hat Software provided lots of patches.
+
+Stelian Pop <stelian@popies.net> is now the current maintainer (since dump-0.4b5).
+
+Thanks to people who reported problems with the port, sent patches, and
+suggested various improvements.
+Here is a partial list of them (if I have forgotten someone, please complain):
+John Adams             johna@onevista.com
+Jin-su Ahn             jsahn@ee.snu.ac.kr
+Eros Albertazzi                eros@lamel.bo.cnr.it
+Matthias Andree                matthias.andree@stud.uni-dortmund.de
+Andrea Arcangeli       andrea@suse.de
+Stephen Atwell         satwell@urbana.css.mot.com
+Gerd Bavendiek         bav@epost.de
+Fabrice Bellet         fabrice@bellet.info
+Stan Bubrouski         satan@fastdial.net
+Stephen Carr           sgcarr@civeng.adelaide.edu.au
+Mike Castle            dalgoda@users.sourceforge.net
+Rob Cermak             cermak@ahab.rutgers.edu
+Antonios Christofides  A.Christofides@itia.ntua.gr
+Isaac Chuang           ike@isl.stanford.edu
+Rainer Clasen          bj@ncc.cicely.de
+Tony Clayton           tonyc@e-smith.com
+W. Reilly Cooley       wcooley@nakedape.cc
+Chris Danis            screechco@home.com
+Abhijit Dasgupta       abhijit@ans.net
+John R. Dennison       gerdesas@users.sourceforge.net
+Eugenio Diaz           getnito@yahoo.com
+Andreas Dilger         adilger@turbolinux.com
+Andrew Donkin          ard@waikato.ac.nz
+Greg Edwards           gedwards@users.sourceforge.net
+Bernhard Erdmann       bernhard.erdmann@gmx.de
+Jason Fearon           jasonf@netrider.org.au
+Jeremy Fitzhardinge    jeremy@goop.org
+Eirik Fuller           eirik@netcom.com
+Arcady Genkin          antipode@users.sourceforge.net
+Uwe Gohlke             uwe@ugsoft.de
+Ian Gordon             iangordon@users.sourceforge.net
+Ted Grzesik            tedgyz@roostme.com
+Mike Harris            mharris@redhat.com
+Andreas Hasenack       andreas@conectiva.com.br
+Christian Haul         haul@informatik.tu-darmstadt.de
+George Helffrich       george@geology.bristol.ac.uk
+Patrick Higgins                phiggins@transzap.com
+Kjetil Torgrim Homme   kjetilho@ifi.uio.no
+Raphael Jaffey         rjaffey@artic.edu
+Jean-Paul van der Jagt jeanpaul@dutepp0.et.tudelft.nl
+Helmut Jarausch                jarausch@igpm.rwth-aachen.de
+Eric Jergensen         eric@dvns.com
+Jeff Johnson           jbj@redhat.com
+Richard Johnson                Richard.Johnson3@ey.com
+Richard Jones           rich@annexia.org
+Zhang Jun              zhangjun@nanjing-fnst.com
+Charles Karney         karney@users.sourceforge.net
+Henry Katz             hkatz@hkatz.dialup.access.net
+Dragan Krnic           dkrnic@lycos.com
+Klaus Kudielka         kkudielk@cacofonix.nt.tuwien.ac.at
+Thorsten Kukuk         kukuk@suse.de
+Ken Lalonde            ken@globalremit.com
+Florian La Roche       florian@jurix.jura.uni-sb.de
+Kari Lempiainen                kari@funky.pp.fi
+Ambrose Li             acli@mingpaoxpress.com
+Georg Lippold          g_lippold@sourceforge.net
+Patrick J. LoPresti    patl@cag.lcs.mit.edu
+Bruce Lowekamp         lowekamp@users.sourceforge.net
+Greg Lutz              greglutz@ix.netcom.com
+Eric Maisonobe         virnet@nat.fr
+Kai Makisara           Kai.Makisara@kolumbus.fi
+Andy Mentges           amentges@jumpline.com
+David Miller           davem@caip.rutgers.edu
+Elliott Mitchell       ehem@m5p.com
+David Monro            davidm@cs.su.oz.au
+Dejan Muhamedagic      dejan@quant-x.com
+Lukas Nellen           L.Nellen@ThPhys.Uni-Heidelberg.DE
+Markus Oberhumer       markus@oberhumer.com
+Nuno Oliveira          nuno@eq.uc.pt
+Brent Olson            night@halcyon.com
+Jorgen Ostling         jorgen_ostling@users.sourceforge.net
+Jerry Peters           gapeters@worldnet.att.net
+David B. Peterson      dave@toppledwagon.com
+Trent Piepho           xyzzy@speakeasy.org
+Dave Platt             dplatt@snulbug.mtview.ca.us
+Kenneth Porter         shiva@well.com
+Eric S. Raymond                esr@minx.thyrsus.com
+Graham Reed            greed@users.sourceforge.net
+Gunther Reiszig                gunther@mit.edu
+David Ronis            ronis@ronispc.chem.mcgill.ca
+Dietrich Rothe         d-rothe@users.sourceforge.net
+Bernhard Sadlowski     sadlowsk@Mathematik.Uni-Bielefeld.DE
+Peter Samuel           peters@e-smith.com
+Jan Sanislo            oystr@cs.washington.edu
+Jörg Schilling         schilling@fokus.gmd.de
+Patrik Schindler       poc@pocnet.net
+Gunther Schlegel       schlegel@riege.de
+Chris Siebenmann       cks@utcc.utoronto.ca
+Paul Slootman          paul@debian.org
+Bob Snyder             rsnyder@janet.advsys.com
+Jeffrey Sofferin       sofferin@users.sourceforge.net
+Gabriel Somlo          somlo@cs.colostate.edu
+Clemens Stiglechner    a9401816@unet.univie.ac.at
+Michal Szymanski       msz@astrouw.edu.pl
+Matti Taskinen         mkt@rni.helsinki.fi
+Jason L Tibbitts III   tibbs@math.uh.edu
+Mike Tibor             tibor@lib.uaa.alaska.edu
+Dirk Traenapp          dtraenapp@users.sourceforge.net
+Erik Troan             ewt@redhat.com
+Philippe Troin         phil@fifi.org
+Theodore Y. Ts'o       tytso@valinux.com
+Stephen Tweedie                sct@dcs.ed.ac.uk
+Matus Uhlar            uhlar@fantomas.sk
+Amith Varghese         amithv@yahoo.com
+Daniel Veillard                Daniel.Veillard@imag.fr
+Jason Venner           jason@idiom.com
+John I Wang            jiwang@users.sourceforge.net
+Christian Weisgerber   naddy@mips.rhein-neckar.de
+Kim Yong-jun           loveyou@hackerslab.org
+John Yu                        jky@it.bu.edu
+Ian Zimmerman          itz@speakeasy.org
+Florian Zumbiehl       florz@gmx.de
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..d3d4102
--- /dev/null
+++ b/TODO
@@ -0,0 +1,37 @@
+$Id: TODO,v 1.24 2002/01/25 14:59:53 stelian Exp $
+
+Need to verify:
+---------------
+
+1.     Verify that dump works with kerberos authentification (this
+       was ported from *BSD and was not tested - in fact, this
+       wasn't even compiled in!). Need success reports for this.
+
+Urgent items (for the next stable version):
+-------------------------------------------
+
+All others:
+-----------
+
+1.     More documentation? Examples, crontab?
+
+2.     Explore and correct dump problems on active filesystems 
+       (lseek/read negative count) (This should be OK as of 0.4b14.
+       Unfortunately, this seems to continue for a very few users).
+
+3.     Reimplement the ext2 specific code in a "backend" and
+       make the dump code more generic. This would allow creation
+       of other backends for other filesystems. Implementing a 
+       (v)fat backend should be quite easy, as for BSD ffs (we
+       already have the code for this). The BSD code in traverse.c
+       (all those #ifdef _BSD) should go into the ffs backend.
+
+4.     Implement a DEBUG option which doesn't fork on each tape, making
+       it able to debug dump with gdb.
+
+5.     Make a bootable dump tape? I don't know if it is possible...
+
+6.     EA/ACL support in dump (requested by Michael Ju. Tokarev 
+       <mjt@tls.msk.ru>.
+
+7.     Better readline completition in restore (escape spaces etc).
diff --git a/common/Makefile.in b/common/Makefile.in
new file mode 100644 (file)
index 0000000..80ea04d
--- /dev/null
@@ -0,0 +1,33 @@
+# $Id: Makefile.in,v 1.5 2003/05/08 21:11:39 stelian Exp $
+
+top_srcdir=    @top_srcdir@
+srcdir=                @srcdir@
+top_builddir=  ..
+
+@MCONFIG@
+
+INC=           -I$(top_srcdir)/dump
+ALL_CFLAGS=    @CPPFLAGS@ @CFLAGS@ @CCOPTS@ -pipe $(OPT) $(GINC) $(INC) $(DEFS) @DUMPDEBUG@
+ALL_LDFLAGS=   @LDFLAGS@ @LDOPTS@ @STATIC@
+SRCS=          dumprmt.c
+OBJS=          dumprmt.o
+
+.c.o:
+       $(CC) -c $(ALL_CFLAGS) $< -o $@
+
+all::          $(OBJS)
+
+install::
+
+clean::
+       $(RM) -f \#* *.s *.o *.a *~ core
+
+distclean::    clean
+       $(RM) -f Makefile Makefile.old .depend
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+
diff --git a/common/dumprmt.c b/common/dumprmt.c
new file mode 100644 (file)
index 0000000..7f88f63
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1980, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: dumprmt.c,v 1.28 2003/10/26 16:05:45 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <sys/param.h>
+#include <sys/mtio.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#ifdef __linux__
+#include <sys/types.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <bsdcompat.h>
+#include <signal.h>
+#elif defined sunos
+#include <sys/vnode.h>
+
+#include <ufs/inode.h>
+#else
+#include <ufs/ufs/dinode.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <protocols/dumprestore.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <compaterr.h>
+#include <rmtflags.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include <pathnames.h>
+#include "dump.h"      /* for X_STARTUP, X_ABORT etc */
+
+#define        TS_CLOSED       0
+#define        TS_OPEN         1
+
+static int rmtstate = TS_CLOSED;
+static int tormtape = -1;
+static int fromrmtape = -1;
+int rshpid = -1;
+static const char *rmtpeer = 0;
+
+static int okname __P((const char *));
+static OFF_T rmtcall __P((const char *, const char *));
+static void rmtconnaborted __P((int));
+static int rmtgetb __P((void));
+static int rmtgetconn __P((void));
+static void rmtgets __P((char *, size_t));
+static OFF_T rmtreply __P((const char *));
+static  int piped_child __P((const char **command));
+#ifdef KERBEROS
+int    krcmd __P((char **, int /*u_short*/, char *, char *, int *, char *));
+#endif
+
+static int errfd = -1;
+extern int dokerberos;
+extern int ntrec;              /* blocking factor on tape */
+extern int abortifconnerr;     /* set to 1 if this lib should exit on connection errors
+                                otherwise just print a message using msg */
+#ifndef errno
+extern int errno;
+#endif
+
+int
+rmthost(const char *host)
+{
+       if (rmtpeer)
+               free((void *)rmtpeer);
+       if ((rmtpeer = strdup(host)) == NULL)
+               rmtpeer = host;
+       signal(SIGPIPE, rmtconnaborted);
+       return rmtgetconn();
+}
+
+static void
+rmtconnaborted(UNUSED(int signo))
+{
+       msg("Lost connection to remote host.\n");
+       if (errfd != -1) {
+               fd_set r;
+               struct timeval t;
+
+               FD_ZERO(&r);
+               FD_SET(errfd, &r);
+               t.tv_sec = 0;
+               t.tv_usec = 0;
+               if (select(errfd + 1, &r, NULL, NULL, &t)) {
+                       int i;
+                       char buf[2048];
+
+                       if ((i = read(errfd, buf, sizeof(buf) - 1)) > 0) {
+                               buf[i] = '\0';
+                               msg("on %s: %s%s", rmtpeer, buf,
+                                       buf[i - 1] == '\n' ? "" : "\n");
+                       }
+               }
+       }
+       if (abortifconnerr)
+               exit(X_ABORT);
+}
+
+static int
+rmtgetconn(void)
+{
+       char *cp;
+       const char *rmt;
+       static struct servent *sp = NULL;
+       static struct passwd *pwd = NULL;
+       const char *tuser;
+       const char *rsh;
+       int size;
+       int throughput;
+       int on;
+       char *rmtpeercopy;
+
+       rsh = getenv("RSH");
+
+       if (!rsh && sp == NULL) {
+               sp = getservbyname(dokerberos ? "kshell" : "shell", "tcp");
+               if (sp == NULL) {
+                       if (abortifconnerr) {
+                               errx(1, "%s/tcp: unknown service", dokerberos ? "kshell" : "shell");
+                       } else {
+                               msg("%s/tcp: unknown service", dokerberos ? "kshell" : "shell");
+                               return 0;
+                       }
+               }
+       }
+       if (pwd == NULL) {
+               pwd = getpwuid(getuid());
+               if (pwd == NULL) {
+                       if (abortifconnerr) {
+                               errx(1, "who are you?");
+                       } else {
+                               msg("who are you?");
+                               return 0;
+                       }
+               }
+       }
+       if ((cp = strchr(rmtpeer, '@')) != NULL) {
+               tuser = rmtpeer;
+               *cp = '\0';
+               if (!okname(tuser)) {
+                       if (abortifconnerr) {
+                               exit(X_STARTUP);
+                       } else {
+                               return 0;
+                       }
+               }
+               rmtpeer = ++cp;
+       } else
+               tuser = pwd->pw_name;
+       if ((rmt = getenv("RMT")) == NULL)
+               rmt = _PATH_RMT;
+       msg("");
+
+       if (rsh) {
+               const char *rshcmd[6];
+               rshcmd[0] = rsh;
+               rshcmd[1] = rmtpeer;
+               rshcmd[2] = "-l";
+               rshcmd[3] = tuser;
+               rshcmd[4] = rmt;
+               rshcmd[5] = NULL;
+
+               /* Restore the uid and gid. We really don't want
+                * to execute whatever is put into RSH variable with
+                * more priviledges than needed... */
+               setuid(getuid());
+               setgid(getgid());
+
+               if ((rshpid = piped_child(rshcmd)) < 0) {
+                       msg("cannot open connection\n");
+                       return 0;
+               }
+       }
+       else {
+               /* Copy rmtpeer to rmtpeercopy to ignore the
+                  return value from rcmd. I cannot figure if
+                  this is this a bug in rcmd or in my code... */
+               rmtpeercopy = (char *)rmtpeer;
+#ifdef KERBEROS
+               if (dokerberos)
+                       tormtape = krcmd(&rmtpeercopy, sp->s_port, tuser, rmt, &errfd,
+                                      (char *)0);
+               else
+#endif
+                       tormtape = rcmd(&rmtpeercopy, (u_short)sp->s_port, pwd->pw_name,
+                                     tuser, rmt, &errfd);
+               if (tormtape < 0) {
+                       msg("login to %s as %s failed.\n", rmtpeer, tuser);
+                       return 0;
+               }
+               size = ntrec * TP_BSIZE;
+               if (size > 60 * 1024)           /* XXX */
+                       size = 60 * 1024;
+               /* Leave some space for rmt request/response protocol */
+               size += 2 * 1024;
+               while (size > TP_BSIZE &&
+                   setsockopt(tormtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
+                           size -= TP_BSIZE;
+               (void)setsockopt(tormtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
+               throughput = IPTOS_THROUGHPUT;
+               if (setsockopt(tormtape, IPPROTO_IP, IP_TOS,
+                   &throughput, sizeof(throughput)) < 0)
+                       perror("IP_TOS:IPTOS_THROUGHPUT setsockopt");
+               on = 1;
+               if (setsockopt(tormtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
+                       perror("TCP_NODELAY setsockopt");
+               fromrmtape = tormtape;
+       }
+       (void)fprintf(stdout, "Connection to %s established.\n", rmtpeer);
+       return 1;
+}
+
+static int
+okname(const char *cp0)
+{
+       const char *cp;
+       int c;
+
+       for (cp = cp0; *cp; cp++) {
+               c = *cp;
+               if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
+                       warnx("invalid user name %s\n", cp0);
+                       return (0);
+               }
+       }
+       return (1);
+}
+
+int
+rmtopen(const char *tape, const int mode)
+{
+       char buf[MAXPATHLEN];
+       char *rmtflags;
+
+       rmtflags = rmtflags_tochar(mode);
+       (void)snprintf(buf, sizeof (buf), "O%s\n%d %s\n", 
+                      tape, 
+                      mode & O_ACCMODE, 
+                      rmtflags);
+       free(rmtflags);
+       rmtstate = TS_OPEN;
+       return (rmtcall(tape, buf));
+}
+
+void
+rmtclose(void)
+{
+
+       if (rmtstate != TS_OPEN)
+               return;
+       rmtcall("close", "C\n");
+       rmtstate = TS_CLOSED;
+}
+
+int
+rmtread(char *buf, size_t count)
+{
+       char line[30];
+       int n, i;
+       ssize_t cc;
+
+       (void)snprintf(line, sizeof (line), "R%u\n", (unsigned)count);
+       n = rmtcall("read", line);
+       if (n < 0) {
+               /* rmtcall() properly sets errno for us on errors. */
+               errno = n;
+               return (-1);
+       }
+       for (i = 0; i < n; i += cc) {
+               cc = read(fromrmtape, buf+i, n - i);
+               if (cc <= 0)
+                       rmtconnaborted(0);
+       }
+       return (n);
+}
+
+int
+rmtwrite(const char *buf, size_t count)
+{
+       char line[30];
+
+       (void)snprintf(line, sizeof (line), "W%ld\n", (long)count);
+       write(tormtape, line, strlen(line));
+       write(tormtape, buf, count);
+       return (rmtreply("write"));
+}
+
+OFF_T
+rmtseek(OFF_T offset, int pos)
+{
+       char line[80];
+
+       (void)snprintf(line, sizeof (line), "L%lld\n%d\n", (long long)offset, pos);
+       return (rmtcall("seek", line));
+}
+
+struct mtget mts;
+
+struct mtget *
+rmtstatus(void)
+{
+       int i;
+       char *cp;
+
+       if (rmtstate != TS_OPEN)
+               return (NULL);
+       i = rmtcall("status", "S");
+       if (i < 0) return NULL;
+       if (i != (int)sizeof(mts)) {
+               msg("mtget sizes different between host (%d) "
+                   "and remote tape (%d)", sizeof(mts), i);
+               for ( /* empty */; i > 0; --i)
+                       rmtgetb();
+               return NULL;
+       }
+       for (i = 0, cp = (char *)&mts; i < (int)sizeof(mts); i++)
+               *cp++ = rmtgetb();
+       return (&mts);
+}
+
+int
+rmtioctl(int cmd, int count)
+{
+       char buf[256];
+
+       if (count < 0)
+               return (-1);
+       (void)snprintf(buf, sizeof (buf), "I%d\n%d\n", cmd, count);
+       return (rmtcall("ioctl", buf));
+}
+
+static OFF_T
+rmtcall(const char *cmd, const char *buf)
+{
+
+       if (write(tormtape, buf, strlen(buf)) != (ssize_t)strlen(buf))
+               rmtconnaborted(0);
+       return (rmtreply(cmd));
+}
+
+static OFF_T
+rmtreply(const char *cmd)
+{
+       char *cp;
+       char code[30], emsg[BUFSIZ];
+
+       rmtgets(code, sizeof (code));
+       if (*code == 'E' || *code == 'F') {
+               rmtgets(emsg, sizeof (emsg));
+               msg("%s: %s", cmd, emsg);
+               errno = atoi(code + 1);
+               if (*code == 'F')
+                       rmtstate = TS_CLOSED;
+               return (-1);
+       }
+       if (*code != 'A') {
+               /* Kill trailing newline */
+               cp = code + strlen(code);
+               if (cp > code && *--cp == '\n')
+                       *cp = '\0';
+
+               msg("Protocol to remote tape server botched (code \"%s\").\n",
+                   code);
+               rmtconnaborted(0);
+       }
+       return (OFF_T)(atoll(code + 1));
+}
+
+static int
+rmtgetb(void)
+{
+       char c;
+
+       if (read(fromrmtape, &c, 1) != 1)
+               rmtconnaborted(0);
+       return (c);
+}
+
+/* Get a line (guaranteed to have a trailing newline). */
+static void
+rmtgets(char *line, size_t len)
+{
+       char *cp = line;
+
+       while (len > 1) {
+               *cp = rmtgetb();
+               if (*cp == '\n') {
+                       cp[1] = '\0';
+                       return;
+               }
+               cp++;
+               len--;
+       }
+       *cp = '\0';
+       msg("Protocol to remote tape server botched.\n");
+       msg("(rmtgets got \"%s\").\n", line);
+       rmtconnaborted(0);
+}
+
+int piped_child(const char **command) {
+       int pid;
+       int to_child_pipe[2];
+       int from_child_pipe[2];
+
+       if (pipe (to_child_pipe) < 0) {
+               msg ("cannot create pipe: %s\n", strerror(errno));
+               return -1;
+       }
+       if (pipe (from_child_pipe) < 0) {
+               msg ("cannot create pipe: %s\n", strerror(errno)); 
+               return -1;
+       }
+       pid = fork ();
+       if (pid < 0) {
+               msg ("cannot fork: %s\n", strerror(errno));
+               return -1;
+       }
+       if (pid == 0) {
+               if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0) {
+                       msg ("cannot dup2 pipe: %s\n", strerror(errno));
+                       exit(1);
+               }
+               if (close (to_child_pipe[1]) < 0) {
+                       msg ("cannot close pipe: %s\n", strerror(errno));
+                       exit(1);
+               }
+               if (close (from_child_pipe[0]) < 0) {
+                       msg ("cannot close pipe: %s\n", strerror(errno));
+                       exit(1);
+               }
+               if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0) {
+                       msg ("cannot dup2 pipe: %s\n", strerror(errno));
+                       exit(1);
+               }
+               setpgid(0, getpid());
+               execvp (command[0], (char *const *) command);
+               msg("cannot exec %s: %s\n", command[0], strerror(errno));
+               exit(1);
+       }
+       if (close (to_child_pipe[0]) < 0) {
+               msg ("cannot close pipe: %s\n", strerror(errno));
+               return -1;
+       }
+       if (close (from_child_pipe[1]) < 0) {
+               msg ("cannot close pipe: %s\n", strerror(errno));
+               return -1;
+       }
+       tormtape = to_child_pipe[1];
+       fromrmtape = from_child_pipe[0];
+       return pid;
+}
diff --git a/compat/include/Makefile.in b/compat/include/Makefile.in
new file mode 100644 (file)
index 0000000..6fbfe48
--- /dev/null
@@ -0,0 +1,24 @@
+# $Id: Makefile.in,v 1.4 2003/01/24 11:01:48 stelian Exp $
+
+top_srcdir=    @top_srcdir@
+srcdir=                @srcdir@
+top_builddir=  ../..
+
+@MCONFIG@
+
+all::
+
+install::
+
+clean::
+       $(RM) -f \#* *~ core
+
+distclean::    clean
+       $(RM) -f Makefile Makefile.old .depend
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+
diff --git a/compat/include/bsdcompat.h b/compat/include/bsdcompat.h
new file mode 100644 (file)
index 0000000..4b9b907
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: bsdcompat.h,v 1.23 2004/07/01 09:14:48 stelian Exp $
+ */
+
+#include <config.h>
+#include <sys/time.h>
+#include <dirent.h>
+#include <ext2fs/ext2fs.h>
+
+#define        __dead          volatile
+#define UNUSED(x)      x __attribute__ ((unused))
+
+#ifndef        NBBY
+#define NBBY           8
+#endif
+
+#ifndef        MIN
+#define MIN(a,b)       ((a < b) ? a : b)
+#endif
+
+#define        WINO            1
+#define        DEV_BSIZE       512
+#define        DEV_BSHIFT      9
+
+#ifndef sunos
+#define        MAXBSIZE        EXT2_MAX_BLOCK_SIZE
+#define ROOTINO                EXT2_ROOT_INO
+#else
+#define ROOTINO                2
+#endif
+#ifdef EXT2_NODUMP_FL
+#define UF_NODUMP      EXT2_NODUMP_FL
+#endif
+
+#ifndef howmany
+#define howmany(x,y)   (((x)+((y)-1))/(y))
+#endif
+#ifndef roundup
+#define roundup(x, y)  ((((x)+((y)-1))/(y))*(y))
+#endif
+#ifndef powerof2
+#define powerof2(x)    ((((x)-1)&(x))==0)
+#endif
+
+#define fsbtodb(sb,b)  ((ext2_loff_t)(((long long)(b) * EXT2_BLOCK_SIZE((sb)->super)) / DEV_BSIZE))
+#define dbtofsb(sb,b)  ((int)(((long long)(b) * DEV_BSIZE) / EXT2_BLOCK_SIZE((sb)->super)))
+
+#define        sblock          fs
+#define fs_fsize       fragsize
+#define fs_bsize       blocksize
+#define fs_size                super->s_blocks_count
+
+#define        IFMT            S_IFMT
+#define IFLNK          S_IFLNK
+#define IFREG          S_IFREG
+#define IFDIR          S_IFDIR
+#define IFCHR          S_IFCHR
+#define IFBLK          S_IFBLK
+#define IFSOCK         S_IFSOCK
+#define IFIFO          S_IFIFO
+
+#if 0
+typedef __s64          quad_t;
+typedef __u64          u_quad_t;
+#endif
+
+/*
+ * The BSD dump format reserves 4 bytes for a time_t, but other architectures
+ * (notably axp) have larger time_t.  ctime4() is a modified ctime() which
+ * always accepts short 4-byte times.
+ */
+#define ctime4(timep) ({ time_t t = *(timep); ctime(&t); })
+
+/*
+ * This is the ext2_inode structure but the fields have been renamed
+ * to match 4.4BSD's names
+ */
+#define        NDADDR          12
+#define        NIADDR           3
+
+#define NINDIR(fs)     EXT2_ADDR_PER_BLOCK(fs->super)
+
+#ifdef sunos
+typedef uint8_t __u8;
+typedef uint16_t __u16;
+typedef uint32_t __u32;
+typedef int8_t __s8;
+typedef int16_t __s16;
+typedef int32_t __s32;
+#ifndef u_int
+typedef unsigned int u_int;
+#endif
+#ifndef u_int16_t
+typedef unsigned short u_int16_t;
+#endif
+#ifndef u_char
+typedef unsigned char u_char;
+#endif
+typedef int64_t quad_t;
+#endif /* sunos */
+
+struct dinode {
+       __u16   di_mode;
+       __u16   di_uid;
+       __u32   di_size;
+       __u32   di_atime;
+       __u32   di_ctime;
+       __u32   di_mtime;
+       __u32   di_dtime;
+       __u16   di_gid;
+       __u16   di_nlink;
+       __u32   di_blocks;
+       __u32   di_flags;
+       __u32   di_reserved1;
+       __u32   di_db[NDADDR];
+       __u32   di_ib[NIADDR];
+       __u32   di_gen;
+       __u32   di_file_acl;
+       __u32   di_dir_acl;
+       __u32   di_faddr;
+       __u8    di_frag;
+       __u8    di_fsize;
+       __u16   di_pad1;
+       __u16   di_uidhigh;
+       __u16   di_gidhigh;
+       __u32   di_spare;
+};
+
+#define di_rdev                di_db[0]
+/* #define di_ouid             di_uid */
+/* #define di_ogid             di_gid */
+#define di_size_high   di_dir_acl
+
+/*
+ * This is the ext2_dir_entry structure but the fields have been renamed
+ * to match 4.4BSD's names
+ *
+ * This is the 4.4BSD directory entry structure
+ */
+#define DIRBLKSIZ      DEV_BSIZE
+#ifndef MAXNAMLEN
+#define MAXNAMLEN      255
+#endif
+
+#ifdef sunos
+#define MAXNAMLEN      255
+#endif
+
+/*
+ * For old libc.
+ */
+#ifndef DT_UNKNOWN
+#define DT_UNKNOWN      0
+#define DT_FIFO                 1
+#define DT_CHR          2
+#define DT_DIR          4
+#define DT_BLK          6
+#define DT_REG          8
+#define DT_LNK         10
+#define DT_SOCK                12
+
+#ifdef sunos
+#define DT_WHT         14
+#endif
+#endif
+
+#ifndef d_fileno
+#define d_fileno d_ino
+#endif
+
+/*
+ * The direct structure used by dump/restore.
+ */
+struct direct {
+       __u32   d_ino;
+       __u16   d_reclen;
+       __u8    d_type;
+       __u8    d_namlen;
+       char    d_name[MAXNAMLEN + 1];
+};
+/*
+ * Convert between stat structure types and directory types.
+ */
+#define IFTODT(mode)   (((mode) & 0170000) >> 12)
+#define DTTOIF(dirtype)        ((dirtype) << 12)
+
+/*
+ * The DIRSIZ macro gives the minimum record length which will hold
+ * the directory entry.  This requires the amount of space in struct direct
+ * without the d_name field, plus enough space for the name with a terminating
+ * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ */
+#ifdef __linux__
+#if    0
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#define DIRSIZ(oldfmt, dp) \
+    ((oldfmt) ? \
+    ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_type+1 + 3) &~ 3)) : \
+    ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)))
+#else /* BYTE_ORDER */
+#define DIRSIZ(oldfmt, dp) \
+    ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+#endif
+#else /* 0 */
+#define DIRSIZ(oldfmt,dp)      EXT2_DIR_REC_LEN(((dp)->d_namlen & 0xff) + 1)
+#endif
+#else /* __linux__ */
+#define DIRSIZ(oldfmt, dp) \
+       ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+#endif
+
+/*
+ * This is the old (Net/2) BSD inode structure
+ * copied from the FreeBSD 1.1.5.1 <ufs/dinode.h> include file
+ */
+#define        MAXFASTLINK     (((NDADDR + NIADDR) * sizeof(unsigned long)) - 1)
+
+struct old_bsd_inode {
+       __u16           di_mode;
+       __s16           di_nlink;
+       __u16           di_uid;
+       __u16           di_gid;
+#if    1
+       union {
+               u_quad_t        v;
+               __u32           val[2];
+       }               di_qsize;
+#else
+       u_quad_t        di_size;
+#endif
+       __u32           di_atime;
+       __s32           di_atspare;
+       __u32           di_mtime;
+       __s32           di_mtspare;
+       __u32           di_ctime;
+       __s32           di_ctspare;
+#if    0
+       union {
+               struct {
+                       daddr_t di_udb[NDADDR];
+                       daddr_t di_uib[NIADDR];
+               } di_addr;
+               char    di_usymlink[MAXFASTLINK + 1];
+       }               di_un;
+#else
+       __u32           di_db[NDADDR];
+       __u32           di_ib[NIADDR];
+#endif
+       __s32           di_flags;
+       __s32           di_blocks;
+       __s32           di_gen;
+       __u32           di_spare[4];
+};
+
+struct bsdtimeval {    /* XXX alpha-*-linux is deviant */
+       __u32   tv_sec;
+       __u32   tv_usec;
+};
+
+/*
+ * This is the new (4.4) BSD inode structure
+ * copied from the FreeBSD 2.0 <ufs/ufs/dinode.h> include file
+ */
+struct new_bsd_inode {
+       __u16           di_mode;
+       __s16           di_nlink;
+       union {
+               __u16           oldids[2];
+               __u32           inumber;
+       }               di_u;
+       u_quad_t        di_size;
+       struct bsdtimeval       di_atime;
+       struct bsdtimeval       di_mtime;
+       struct bsdtimeval       di_ctime;
+       __u32           di_db[NDADDR];
+       __u32           di_ib[NIADDR];
+       __u32           di_flags;
+       __s32           di_blocks;
+       __s32           di_gen;
+       __u32           di_uid;
+       __u32           di_gid;
+       __s32           di_spare[2];
+};
+
+#define        di_ouid         di_u.oldids[0]
+#define        di_ogid         di_u.oldids[1]
diff --git a/compat/include/bylabel.h b/compat/include/bylabel.h
new file mode 100644 (file)
index 0000000..baa334a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
+ *      - added Native Language Support
+ *     2000-01-20 James Antill <james@and.org>
+ *      - Added error message if /proc/partitions cannot be opened
+ *     2000-05-09 Erik Troan <ewt@redhat.com>
+ *     - Added cache for UUID and disk labels
+ *     Wed Aug 16 2000 Erik Troan <ewt@redhat.com>
+ *     - Ported to dump/restore
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: bylabel.h,v 1.6 2004/07/05 15:02:36 stelian Exp $
+ */
+
+#ifndef _BYLABEL_H_
+#define        _BYLABEL_H_
+
+#include <config.h>
+
+#ifdef HAVE_BLKID
+
+#include <blkid/blkid.h>
+
+static inline const char * get_device_name(const char * item) {
+       return blkid_get_devname(NULL, item, NULL);
+}
+
+static inline const char * get_device_label(const char * spec) {
+       return blkid_get_tag_value(NULL, "LABEL", spec);
+}
+       
+#else
+
+const char * get_device_name(const char * item);
+const char * get_device_label(const char * spec);
+
+#endif
+
+#endif /* !_BYLABEL_H_ */
diff --git a/compat/include/compaterr.h b/compat/include/compaterr.h
new file mode 100644 (file)
index 0000000..14e6671
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: compaterr.h,v 1.10 2003/03/30 15:40:34 stelian Exp $
+ */
+
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _COMPATERR_H_
+#define        _COMPATERR_H_
+
+#include <config.h>
+
+#if defined(HAVE_ERR) || defined(HAVE_ERRX) || defined(HAVE_VERR) || defined(HAVE_VERRX) || defined(HAVE_VWARN) || defined(HAVE_VWARNX) || defined(HAVE_WARN) || defined(HAVE_WARNX)
+#include <err.h>
+#endif
+
+#include <sys/cdefs.h>
+
+#include <stdarg.h>
+
+#ifndef        _BSD_VA_LIST_
+#define _BSD_VA_LIST_          va_list
+#endif
+
+#ifndef        __dead
+#define __dead                 volatile
+#endif
+
+__BEGIN_DECLS
+#ifndef HAVE_ERR
+__dead void    err __P((int, const char *, ...));
+#endif
+#ifndef HAVE_VERR
+__dead void    verr __P((int, const char *, _BSD_VA_LIST_));
+#endif
+#ifndef HAVE_ERRX
+__dead void    errx __P((int, const char *, ...));
+#endif
+#ifndef HAVE_VERRX
+__dead void    verrx __P((int, const char *, _BSD_VA_LIST_));
+#endif
+#ifndef HAVE_WARN
+void           warn __P((const char *, ...));
+#endif
+#ifndef HAVE_VWARN
+void           vwarn __P((const char *, _BSD_VA_LIST_));
+#endif
+#ifndef HAVE_WARNX
+void           warnx __P((const char *, ...));
+#endif
+#ifndef HAVE_VWARNX
+void           vwarnx __P((const char *, _BSD_VA_LIST_));
+#endif
+__END_DECLS
+
+#endif /* !_COMPATERR_H_ */
diff --git a/compat/include/compatglob.h b/compat/include/compatglob.h
new file mode 100644 (file)
index 0000000..df2a536
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: compatglob.h,v 1.9 2003/03/30 15:40:34 stelian Exp $
+ */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _COMPATGLOB_H_
+#define        _COMPATGLOB_H_
+
+#include <config.h>
+
+#ifdef HAVE_GLOB
+#include <glob.h>
+#else
+
+#include <sys/cdefs.h>
+
+struct stat;
+typedef struct {
+       int gl_pathc;           /* Count of total paths so far. */
+       int gl_matchc;          /* Count of paths matching pattern. */
+       int gl_offs;            /* Reserved at beginning of gl_pathv. */
+       int gl_flags;           /* Copy of flags parameter to glob. */
+       char **gl_pathv;        /* List of paths matching pattern. */
+                               /* Copy of errfunc parameter to glob. */
+       int (*gl_errfunc) __P((const char *, int));
+
+       /*
+        * Alternate filesystem access methods for glob; replacement
+        * versions of closedir(3), readdir(3), opendir(3), stat(2)
+        * and lstat(2).
+        */
+       void (*gl_closedir) __P((void *));
+       struct dirent *(*gl_readdir) __P((void *));     
+       void *(*gl_opendir) __P((const char *));
+       int (*gl_lstat) __P((const char *, struct stat *));
+       int (*gl_stat) __P((const char *, struct stat *));
+} glob_t;
+
+#define        GLOB_APPEND     0x0001  /* Append to output from previous call. */
+#define        GLOB_DOOFFS     0x0002  /* Use gl_offs. */
+#define        GLOB_ERR        0x0004  /* Return on error. */
+#define        GLOB_MARK       0x0008  /* Append / to matching directories. */
+#define        GLOB_NOCHECK    0x0010  /* Return pattern itself if nothing matches. */
+#define        GLOB_NOSORT     0x0020  /* Don't sort. */
+
+#define        GLOB_ALTDIRFUNC 0x0040  /* Use alternately specified directory funcs. */
+#define        GLOB_BRACE      0x0080  /* Expand braces ala csh. */
+#define        GLOB_MAGCHAR    0x0100  /* Pattern had globbing characters. */
+#define        GLOB_NOMAGIC    0x0200  /* GLOB_NOCHECK without magic chars (csh). */
+#define        GLOB_QUOTE      0x0400  /* Quote special chars with \. */
+#define        GLOB_TILDE      0x0800  /* Expand tilde names from the passwd file. */
+
+#define        GLOB_NOSPACE    (-1)    /* Malloc call failed. */
+#define        GLOB_ABEND      (-2)    /* Unignored error. */
+
+__BEGIN_DECLS
+int    glob __P((const char *, int, int (*)(const char *, int), glob_t *));
+void   globfree __P((glob_t *));
+__END_DECLS
+
+#endif /* HAVE_GLOB */
+
+#endif /* !_COMPATGLOB_H_ */
diff --git a/compat/include/compatlfs.h b/compat/include/compatlfs.h
new file mode 100644 (file)
index 0000000..fe7db5f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: compatlfs.h,v 1.5 2004/03/29 13:57:29 stelian Exp $
+ */
+
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _COMPATLFS_H_
+#define        _COMPATLFS_H_
+
+#include <config.h>
+
+#ifdef USE_LFS
+
+#define _LARGEFILE64_SOURCE
+#define OPEN open64
+#define LSEEK lseek64
+#define STAT stat64
+#define LSTAT lstat64
+#define FTRUNCATE ftruncate64
+#define OFF_T __off64_t
+#define MKSTEMP mkstemp64
+#define FTELL ftello64
+
+#else
+
+#define OPEN open
+#define LSEEK lseek
+#define STAT stat
+#define LSTAT lstat
+#define FTRUNCATE ftruncate
+#define OFF_T off_t
+#define MKSTEMP mkstemp
+#define FTELL ftell
+
+#endif /* USE_LFS */
+
+#endif /* !_COMPATLFS_H_ */
diff --git a/compat/include/darwin.h b/compat/include/darwin.h
new file mode 100644 (file)
index 0000000..bcab1ab
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ *
+ */
+
+#if defined(DUMP_MACOSX)
+
+#ifndef DARWIN_H
+#define DARWIN_H
+
+#define INFOLEN 32
+#define CORRECT 2
+
+
+#define DARWIN_RSRC_NAME "/..namedfork/rsrc"
+#define DARWIN_FINFO_NAME "/..namedfork/finfo"
+/*
+ * some structs from the HFS+ info for OS X
+ * - including the header file causes messy clashes
+ */
+
+struct FndrFileInfo {
+    u_int32_t     fdType;        /* file type */
+    u_int32_t     fdCreator;    /* file creator */
+    u_int16_t     fdFlags;    /* Finder flags */
+    struct {
+        int16_t    v;        /* file's location */
+        int16_t    h;
+    } fdLocation;
+    int16_t     opaque;
+};
+typedef struct FndrFileInfo FndrFileInfo;
+
+struct FndrDirInfo {
+        struct {                        /* folder's window rectangle */
+            int16_t     top;
+            int16_t     left;
+            int16_t     bottom;
+            int16_t     right;
+        } frRect;
+        unsigned short  frFlags;        /* Finder flags */
+        struct {
+            u_int16_t   v;              /* folder's location */
+            u_int16_t   h;
+        } frLocation;
+        int16_t         opaque;
+};
+typedef struct FndrDirInfo FndrDirInfo;
+
+
+struct FndrOpaqueInfo {
+    int8_t opaque[16];
+};
+typedef struct FndrOpaqueInfo FndrOpaqueInfo;
+
+struct fndrinfo_block_t {
+        FndrFileInfo    finderInfo;
+        FndrOpaqueInfo  extendedFinderInfo;
+};
+typedef struct fndrinfo_block_t fndrinfo_block_t;
+
+struct attrinfo_block_t {
+        unsigned long info_length;
+       u_int32_t       objid_low;
+       u_int32_t       objid_high;
+       struct timespec created;
+       struct timespec backup;
+       union {
+               fndrinfo_block_t        finfo;
+               FndrDirInfo             dinfo;
+        } o;
+       off_t   rsrc_length;
+};
+typedef struct attrinfo_block_t attrinfo_block_t;
+
+
+#define ASINGLE_MAGIC  0x00051600      /* all in one file */
+#define ADOUBLE_MAGIC  0x00051607      /* resource + info, data separated */
+
+#define ASD_VERSION1   0x00010000      /* the original version */
+#define ASD_VERSION2   0x00020000      /* the second version */
+
+typedef struct ASDHeader {
+       u_long  magic;                  /* either single or double */
+       u_long  version;                /* ASD_VERSION2 */
+       u_char  filler[16];             /* reserved, zero */
+       u_short entries;                /* the number of entries */
+       /* the entries follow */
+} ASDHeader, *ASDHeaderPtr, **ASDHeaderHandle;
+
+typedef enum {
+       EntryDataFork = 1,
+       EntryRSRCFork,
+       EntryRealName,
+       EntryComment,
+       EntryBWIcon,
+       EntryColorIcon,
+       EntryOldFileInfo,
+       EntryFileDates,
+       EntryFinderInfo,
+       EntryMacFileInfo,
+       EntryProDOSInfo,
+       EntryMSDOSInfo,
+       EntryShortName,
+       EntryAFPFileInfo,
+       EntryDirID
+} ASDEntryType;
+
+typedef struct {
+       u_long  entryID;                /* the entry type (forced to long) */
+       u_long  offset;                 /* offset in file of entry */
+       u_long  len;                    /* length of entry */
+} ASDEntry, *ASDEntryPtr, **ASDEntryHandle;
+
+typedef struct {
+       u_long  creationDate;
+       u_long  modificationDate;
+       u_long  backupDate;
+       u_long  accessDate;
+} FileDates, *FileDatesPtr;
+
+typedef struct dumpfinderinfo {
+ FndrFileInfo fndrinfo;        /* 0: size = 16 bytes, same for FndrDirInfo */
+ u_int32_t createDate; /* 16: date and time of creation */
+ u_int32_t contentModDate;/* 20: date/time of last content modification */
+ u_int32_t attributeModDate;/* 24: date/time of last attribute modification */
+ u_int32_t accessDate; /* 30: date/time of last access (MacOS X only) */
+ u_int32_t backupDate; /* 34: date/time of last backup */
+ u_int32_t textEncoding;       /* 36: hint for name conversions */
+ char filler[980]; /* 40: for later expansion, 40 + 980 - 4 = TP_BSIZE - 4 */
+} DumpFinderInfo, *DumpFinderInfoPtr;
+
+#endif /* DARWIN_H */
+#endif
diff --git a/compat/include/lzoconf.h b/compat/include/lzoconf.h
new file mode 100644 (file)
index 0000000..96db180
--- /dev/null
@@ -0,0 +1,451 @@
+/* lzoconf.h -- configuration for the LZO real-time data compression library
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#ifndef __LZOCONF_H
+#define __LZOCONF_H
+
+#define LZO_VERSION             0x1080
+#define LZO_VERSION_STRING      "1.08"
+#define LZO_VERSION_DATE        "Jul 12 2002"
+
+/* internal Autoconf configuration file - only used when building LZO */
+#if defined(LZO_HAVE_CONFIG_H)
+#  include <config.h>
+#endif
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/***********************************************************************
+// LZO requires a conforming <limits.h>
+************************************************************************/
+
+#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
+#  error "invalid CHAR_BIT"
+#endif
+#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
+#  error "check your compiler installation"
+#endif
+#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
+#  error "your limits.h macros are broken"
+#endif
+
+/* workaround a cpp bug under hpux 10.20 */
+#define LZO_0xffffffffL         4294967295ul
+
+#if !defined(LZO_UINT32_C)
+#  if (UINT_MAX < LZO_0xffffffffL)
+#    define LZO_UINT32_C(c)     c ## UL
+#  else
+#    define LZO_UINT32_C(c)     c ## U
+#  endif
+#endif
+
+
+/***********************************************************************
+// architecture defines
+************************************************************************/
+
+#if !defined(__LZO_WIN) && !defined(__LZO_DOS) && !defined(__LZO_OS2)
+#  if defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows)
+#    define __LZO_WIN
+#  elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
+#    define __LZO_WIN
+#  elif defined(__NT__) || defined(__NT_DLL__) || defined(__WINDOWS_386__)
+#    define __LZO_WIN
+#  elif defined(__DOS__) || defined(__MSDOS__) || defined(MSDOS)
+#    define __LZO_DOS
+#  elif defined(__OS2__) || defined(__OS2V2__) || defined(OS2)
+#    define __LZO_OS2
+#  elif defined(__palmos__)
+#    define __LZO_PALMOS
+#  elif defined(__TOS__) || defined(__atarist__)
+#    define __LZO_TOS
+#  endif
+#endif
+
+#if (UINT_MAX < LZO_0xffffffffL)
+#  if defined(__LZO_WIN)
+#    define __LZO_WIN16
+#  elif defined(__LZO_DOS)
+#    define __LZO_DOS16
+#  elif defined(__LZO_PALMOS)
+#    define __LZO_PALMOS16
+#  elif defined(__LZO_TOS)
+#    define __LZO_TOS16
+#  elif defined(__C166__)
+#  else
+     /* porting hint: for pure 16-bit architectures try compiling
+      * everything with -D__LZO_STRICT_16BIT */
+#    error "16-bit target not supported - contact me for porting hints"
+#  endif
+#endif
+
+#if !defined(__LZO_i386)
+#  if defined(__LZO_DOS) || defined(__LZO_WIN16)
+#    define __LZO_i386
+#  elif defined(__i386__) || defined(__386__) || defined(_M_IX86)
+#    define __LZO_i386
+#  endif
+#endif
+
+#if defined(__LZO_STRICT_16BIT)
+#  if (UINT_MAX < LZO_0xffffffffL)
+#    include <lzo16bit.h>
+#  endif
+#endif
+
+/* memory checkers */
+#if !defined(__LZO_CHECKER)
+#  if defined(__BOUNDS_CHECKING_ON)
+#    define __LZO_CHECKER
+#  elif defined(__CHECKER__)
+#    define __LZO_CHECKER
+#  elif defined(__INSURE__)
+#    define __LZO_CHECKER
+#  elif defined(__PURIFY__)
+#    define __LZO_CHECKER
+#  endif
+#endif
+
+
+/***********************************************************************
+// integral and pointer types
+************************************************************************/
+
+/* Integral types with 32 bits or more */
+#if !defined(LZO_UINT32_MAX)
+#  if (UINT_MAX >= LZO_0xffffffffL)
+     typedef unsigned int       lzo_uint32;
+     typedef int                lzo_int32;
+#    define LZO_UINT32_MAX      UINT_MAX
+#    define LZO_INT32_MAX       INT_MAX
+#    define LZO_INT32_MIN       INT_MIN
+#  elif (ULONG_MAX >= LZO_0xffffffffL)
+     typedef unsigned long      lzo_uint32;
+     typedef long               lzo_int32;
+#    define LZO_UINT32_MAX      ULONG_MAX
+#    define LZO_INT32_MAX       LONG_MAX
+#    define LZO_INT32_MIN       LONG_MIN
+#  else
+#    error "lzo_uint32"
+#  endif
+#endif
+
+/* lzo_uint is used like size_t */
+#if !defined(LZO_UINT_MAX)
+#  if (UINT_MAX >= LZO_0xffffffffL)
+     typedef unsigned int       lzo_uint;
+     typedef int                lzo_int;
+#    define LZO_UINT_MAX        UINT_MAX
+#    define LZO_INT_MAX         INT_MAX
+#    define LZO_INT_MIN         INT_MIN
+#  elif (ULONG_MAX >= LZO_0xffffffffL)
+     typedef unsigned long      lzo_uint;
+     typedef long               lzo_int;
+#    define LZO_UINT_MAX        ULONG_MAX
+#    define LZO_INT_MAX         LONG_MAX
+#    define LZO_INT_MIN         LONG_MIN
+#  else
+#    error "lzo_uint"
+#  endif
+#endif
+
+typedef int lzo_bool;
+
+
+/***********************************************************************
+// memory models
+************************************************************************/
+
+/* Memory model for the public code segment. */
+#if !defined(__LZO_CMODEL)
+#  if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#    define __LZO_CMODEL        __far
+#  elif defined(__LZO_i386) && defined(__WATCOMC__)
+#    define __LZO_CMODEL        __near
+#  else
+#    define __LZO_CMODEL
+#  endif
+#endif
+
+/* Memory model for the public data segment. */
+#if !defined(__LZO_DMODEL)
+#  if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#    define __LZO_DMODEL        __far
+#  elif defined(__LZO_i386) && defined(__WATCOMC__)
+#    define __LZO_DMODEL        __near
+#  else
+#    define __LZO_DMODEL
+#  endif
+#endif
+
+/* Memory model that allows to access memory at offsets of lzo_uint. */
+#if !defined(__LZO_MMODEL)
+#  if (LZO_UINT_MAX <= UINT_MAX)
+#    define __LZO_MMODEL
+#  elif defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#    define __LZO_MMODEL        __huge
+#    define LZO_999_UNSUPPORTED
+#  elif defined(__LZO_PALMOS16) || defined(__LZO_TOS16)
+#    define __LZO_MMODEL
+#  else
+#    error "__LZO_MMODEL"
+#  endif
+#endif
+
+/* no typedef here because of const-pointer issues */
+#define lzo_byte                unsigned char __LZO_MMODEL
+#define lzo_bytep               unsigned char __LZO_MMODEL *
+#define lzo_charp               char __LZO_MMODEL *
+#define lzo_voidp               void __LZO_MMODEL *
+#define lzo_shortp              short __LZO_MMODEL *
+#define lzo_ushortp             unsigned short __LZO_MMODEL *
+#define lzo_uint32p             lzo_uint32 __LZO_MMODEL *
+#define lzo_int32p              lzo_int32 __LZO_MMODEL *
+#define lzo_uintp               lzo_uint __LZO_MMODEL *
+#define lzo_intp                lzo_int __LZO_MMODEL *
+#define lzo_voidpp              lzo_voidp __LZO_MMODEL *
+#define lzo_bytepp              lzo_bytep __LZO_MMODEL *
+
+#ifndef lzo_sizeof_dict_t
+#  define lzo_sizeof_dict_t     sizeof(lzo_bytep)
+#endif
+
+
+/***********************************************************************
+// calling conventions and function types
+************************************************************************/
+
+/* linkage */
+#if !defined(__LZO_EXTERN_C)
+#  ifdef __cplusplus
+#    define __LZO_EXTERN_C      extern "C"
+#  else
+#    define __LZO_EXTERN_C      extern
+#  endif
+#endif
+
+/* calling convention */
+#if !defined(__LZO_CDECL)
+#  if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#    define __LZO_CDECL         __LZO_CMODEL __cdecl
+#  elif defined(__LZO_i386) && defined(_MSC_VER)
+#    define __LZO_CDECL         __LZO_CMODEL __cdecl
+#  elif defined(__LZO_i386) && defined(__WATCOMC__)
+#    define __LZO_CDECL         __LZO_CMODEL __cdecl
+#  else
+#    define __LZO_CDECL         __LZO_CMODEL
+#  endif
+#endif
+#if !defined(__LZO_ENTRY)
+#  define __LZO_ENTRY           __LZO_CDECL
+#endif
+
+/* C++ exception specification for extern "C" function types */
+#if !defined(__cplusplus)
+#  undef LZO_NOTHROW
+#  define LZO_NOTHROW
+#elif !defined(LZO_NOTHROW)
+#  define LZO_NOTHROW
+#endif
+
+
+typedef int
+(__LZO_ENTRY *lzo_compress_t)   ( const lzo_byte *src, lzo_uint  src_len,
+                                        lzo_byte *dst, lzo_uintp dst_len,
+                                        lzo_voidp wrkmem );
+
+typedef int
+(__LZO_ENTRY *lzo_decompress_t) ( const lzo_byte *src, lzo_uint  src_len,
+                                        lzo_byte *dst, lzo_uintp dst_len,
+                                        lzo_voidp wrkmem );
+
+typedef int
+(__LZO_ENTRY *lzo_optimize_t)   (       lzo_byte *src, lzo_uint  src_len,
+                                        lzo_byte *dst, lzo_uintp dst_len,
+                                        lzo_voidp wrkmem );
+
+typedef int
+(__LZO_ENTRY *lzo_compress_dict_t)(const lzo_byte *src, lzo_uint  src_len,
+                                        lzo_byte *dst, lzo_uintp dst_len,
+                                        lzo_voidp wrkmem,
+                                  const lzo_byte *dict, lzo_uint dict_len );
+
+typedef int
+(__LZO_ENTRY *lzo_decompress_dict_t)(const lzo_byte *src, lzo_uint  src_len,
+                                        lzo_byte *dst, lzo_uintp dst_len,
+                                        lzo_voidp wrkmem,
+                                  const lzo_byte *dict, lzo_uint dict_len );
+
+
+/* assembler versions always use __cdecl */
+typedef int
+(__LZO_CDECL *lzo_compress_asm_t)( const lzo_byte *src, lzo_uint  src_len,
+                                        lzo_byte *dst, lzo_uintp dst_len,
+                                        lzo_voidp wrkmem );
+
+typedef int
+(__LZO_CDECL *lzo_decompress_asm_t)( const lzo_byte *src, lzo_uint  src_len,
+                                        lzo_byte *dst, lzo_uintp dst_len,
+                                        lzo_voidp wrkmem );
+
+
+/* a progress indicator callback function */
+typedef void (__LZO_ENTRY *lzo_progress_callback_t) (lzo_uint, lzo_uint);
+
+
+/***********************************************************************
+// export information
+************************************************************************/
+
+/* DLL export information */
+#if !defined(__LZO_EXPORT1)
+#  define __LZO_EXPORT1
+#endif
+#if !defined(__LZO_EXPORT2)
+#  define __LZO_EXPORT2
+#endif
+
+/* exported calling convention for C functions */
+#if !defined(LZO_PUBLIC)
+#  define LZO_PUBLIC(_rettype) \
+                __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_ENTRY
+#endif
+#if !defined(LZO_EXTERN)
+#  define LZO_EXTERN(_rettype)          __LZO_EXTERN_C LZO_PUBLIC(_rettype)
+#endif
+#if !defined(LZO_PRIVATE)
+#  define LZO_PRIVATE(_rettype)         static _rettype __LZO_ENTRY
+#endif
+
+/* exported __cdecl calling convention for assembler functions */
+#if !defined(LZO_PUBLIC_CDECL)
+#  define LZO_PUBLIC_CDECL(_rettype) \
+                __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
+#endif
+#if !defined(LZO_EXTERN_CDECL)
+#  define LZO_EXTERN_CDECL(_rettype)    __LZO_EXTERN_C LZO_PUBLIC_CDECL(_rettype)
+#endif
+
+/* exported global variables (LZO currently uses no static variables and
+ * is fully thread safe) */
+#if !defined(LZO_PUBLIC_VAR)
+#  define LZO_PUBLIC_VAR(_type) \
+                __LZO_EXPORT1 _type __LZO_EXPORT2 __LZO_DMODEL
+#endif
+#if !defined(LZO_EXTERN_VAR)
+#  define LZO_EXTERN_VAR(_type)         extern LZO_PUBLIC_VAR(_type)
+#endif
+
+
+/***********************************************************************
+// error codes and prototypes
+************************************************************************/
+
+/* Error codes for the compression/decompression functions. Negative
+ * values are errors, positive values will be used for special but
+ * normal events.
+ */
+#define LZO_E_OK                    0
+#define LZO_E_ERROR                 (-1)
+#define LZO_E_OUT_OF_MEMORY         (-2)    /* not used right now */
+#define LZO_E_NOT_COMPRESSIBLE      (-3)    /* not used right now */
+#define LZO_E_INPUT_OVERRUN         (-4)
+#define LZO_E_OUTPUT_OVERRUN        (-5)
+#define LZO_E_LOOKBEHIND_OVERRUN    (-6)
+#define LZO_E_EOF_NOT_FOUND         (-7)
+#define LZO_E_INPUT_NOT_CONSUMED    (-8)
+
+
+/* lzo_init() should be the first function you call.
+ * Check the return code !
+ *
+ * lzo_init() is a macro to allow checking that the library and the
+ * compiler's view of various types are consistent.
+ */
+#define lzo_init() __lzo_init2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
+    (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
+    (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
+    (int)sizeof(lzo_compress_t))
+LZO_EXTERN(int) __lzo_init2(unsigned,int,int,int,int,int,int,int,int,int);
+
+/* version functions (useful for shared libraries) */
+LZO_EXTERN(unsigned) lzo_version(void);
+LZO_EXTERN(const char *) lzo_version_string(void);
+LZO_EXTERN(const char *) lzo_version_date(void);
+LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
+LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
+
+/* string functions */
+LZO_EXTERN(int)
+lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len);
+LZO_EXTERN(lzo_voidp)
+lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
+LZO_EXTERN(lzo_voidp)
+lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
+LZO_EXTERN(lzo_voidp)
+lzo_memset(lzo_voidp _s, int _c, lzo_uint _len);
+
+/* checksum functions */
+LZO_EXTERN(lzo_uint32)
+lzo_adler32(lzo_uint32 _adler, const lzo_byte *_buf, lzo_uint _len);
+LZO_EXTERN(lzo_uint32)
+lzo_crc32(lzo_uint32 _c, const lzo_byte *_buf, lzo_uint _len);
+
+/* misc. */
+LZO_EXTERN(lzo_bool) lzo_assert(int _expr);
+LZO_EXTERN(int) _lzo_config_check(void);
+typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
+typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
+typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t;
+
+/* align a char pointer on a boundary that is a multiple of `size' */
+LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
+#define LZO_PTR_ALIGN_UP(_ptr,_size) \
+    ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
+
+/* deprecated - only for backward compatibility */
+#define LZO_ALIGN(_ptr,_size) LZO_PTR_ALIGN_UP(_ptr,_size)
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* already included */
+
diff --git a/compat/include/minilzo.h b/compat/include/minilzo.h
new file mode 100644 (file)
index 0000000..e3270f9
--- /dev/null
@@ -0,0 +1,100 @@
+/* minilzo.h -- mini subset of the LZO real-time data compression library
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+/*
+ * NOTE:
+ *   the full LZO package can be found at
+ *   http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#ifndef __MINILZO_H
+#define __MINILZO_H
+
+#define MINILZO_VERSION         0x1080
+
+#ifdef __LZOCONF_H
+#  error "you cannot use both LZO and miniLZO"
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "lzoconf.h"
+
+#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
+#  error "version mismatch in header files"
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+/* Memory required for the wrkmem parameter.
+ * When the required size is 0, you can also pass a NULL pointer.
+ */
+
+#define LZO1X_MEM_COMPRESS      LZO1X_1_MEM_COMPRESS
+#define LZO1X_1_MEM_COMPRESS    ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
+#define LZO1X_MEM_DECOMPRESS    (0)
+
+
+/* compression */
+LZO_EXTERN(int)
+lzo1x_1_compress        ( const lzo_byte *src, lzo_uint  src_len,
+                                lzo_byte *dst, lzo_uintp dst_len,
+                                lzo_voidp wrkmem );
+
+/* decompression */
+LZO_EXTERN(int)
+lzo1x_decompress        ( const lzo_byte *src, lzo_uint  src_len,
+                                lzo_byte *dst, lzo_uintp dst_len,
+                                lzo_voidp wrkmem /* NOT USED */ );
+
+/* safe decompression with overrun testing */
+LZO_EXTERN(int)
+lzo1x_decompress_safe   ( const lzo_byte *src, lzo_uint  src_len,
+                                lzo_byte *dst, lzo_uintp dst_len,
+                                lzo_voidp wrkmem /* NOT USED */ );
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* already included */
+
diff --git a/compat/include/pathnames.h b/compat/include/pathnames.h
new file mode 100644 (file)
index 0000000..281d204
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: pathnames.h,v 1.14 2003/10/26 16:05:46 stelian Exp $
+ */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <paths.h>
+
+#ifdef __linux__
+#include <sys/mtio.h>  /* use the same default tape as "mt" */
+#define _PATH_DEFTAPE  DEFTAPE
+#endif
+
+#ifndef _PATH_DEFTAPE
+#ifdef __linux__
+#define        _PATH_DEFTAPE   "/dev/st0"
+#endif
+#ifdef sunos
+#define        _PATH_DEFTAPE   "/dev/rmt/0"
+#endif
+#endif
+
+#define        _PATH_RMT       "/etc/rmt"              /* path on remote host */
diff --git a/compat/include/protocols/dumprestore.h b/compat/include/protocols/dumprestore.h
new file mode 100644 (file)
index 0000000..fc43715
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: dumprestore.h,v 1.22 2004/07/01 09:14:49 stelian Exp $
+ */
+
+/*
+ * Copyright (c) 1980, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _PROTOCOLS_DUMPRESTORE_H_
+#define _PROTOCOLS_DUMPRESTORE_H_
+
+#include <config.h>
+
+/*
+ * TP_BSIZE is the size of file blocks on the dump tapes.
+ * Note that TP_BSIZE must be a multiple of DEV_BSIZE.
+ *
+ * NTREC is the number of TP_BSIZE blocks that are written
+ * in each tape record. HIGHDENSITYTREC is the number of
+ * TP_BSIZE blocks that are written in each tape record on
+ * 6250 BPI or higher density tapes.
+ *
+ * TP_NINDIR is the number of indirect pointers in a TS_INODE
+ * or TS_ADDR record. Note that it must be a power of two.
+ */
+#define TP_BSIZE       1024
+#define NTREC          10
+#define HIGHDENSITYTREC        32
+#define TP_NINDIR      (TP_BSIZE/2)
+#define TP_NINOS       (TP_NINDIR / sizeof (int32_t))
+#define LBLSIZE                16
+#define NAMELEN                64
+
+#define OFS_MAGIC      (int)60011
+#define NFS_MAGIC      (int)60012
+#define FS_UFS2_MAGIC   (int)0x19540119
+#define CHECKSUM       (int)84446
+
+#ifdef __linux__
+typedef u_int32_t      dump_ino_t;
+#endif
+
+#ifdef sunos
+typedef unsigned int   dump_ino_t;
+#endif
+
+union u_data {
+       char    s_addrs[TP_NINDIR];     /* 1 => data; 0 => hole in inode */
+       int32_t s_inos[TP_NINOS];       /* table of first inode on each volume */
+} u_data;
+
+union u_spcl {
+       char dummy[TP_BSIZE];
+       struct  s_spcl {
+               int32_t c_type;             /* record type (see below) */
+               int32_t c_date;             /* date of this dump */
+               int32_t c_ddate;            /* date of previous dump */
+               int32_t c_volume;           /* dump volume number */
+               u_int32_t c_tapea;          /* logical block of this record */
+               dump_ino_t c_inumber;       /* number of inode */
+               int32_t c_magic;            /* magic number (see above) */
+               int32_t c_checksum;         /* record checksum */
+#ifdef __linux__
+               struct  new_bsd_inode c_dinode;
+#else
+#ifdef sunos
+               struct  new_bsd_inode c_dinode;
+#else
+               struct  dinode  c_dinode;   /* ownership and mode of inode */
+#endif
+#endif
+               int32_t c_count;            /* number of valid c_addr entries */
+               union u_data c_data;        /* see above */
+               char    c_label[LBLSIZE];   /* dump label */
+               int32_t c_level;            /* level of this dump */
+               char    c_filesys[NAMELEN]; /* name of dumpped file system */
+               char    c_dev[NAMELEN];     /* name of dumpped device */
+               char    c_host[NAMELEN];    /* name of dumpped host */
+               int32_t c_flags;            /* additional information */
+               int32_t c_firstrec;         /* first record on volume */
+               int32_t c_ntrec;            /* blocksize on volume */
+                int32_t        c_extattributes;    /* additional inode info */
+                int32_t        c_spare[30];        /* reserved for future uses */
+       } s_spcl;
+} u_spcl;
+#define spcl u_spcl.s_spcl
+#define c_addr c_data.s_addrs
+#define c_inos c_data.s_inos
+
+/*
+ * special record types
+ */
+#define TS_TAPE        1       /* dump tape header */
+#define TS_INODE       2       /* beginning of file record */
+#define TS_ADDR        4       /* continuation of file record */
+#define TS_BITS        3       /* map of inodes on tape */
+#define TS_CLRI        6       /* map of inodes deleted since last dump */
+#define TS_END         5       /* end of volume marker */
+
+/*
+ * flag values
+ */
+#define DR_NEWHEADER   0x0001  /* new format tape header */
+#define DR_NEWINODEFMT 0x0002  /* new format inodes on tape */
+#define DR_COMPRESSED  0x0080  /* dump tape is compressed */
+#define DR_METAONLY    0x0100  /* only the metadata of the inode has
+                                  been dumped */
+#define DR_INODEINFO   0x0002  /* TS_END header contains c_inos information */
+#define DR_EXTATTRIBUTES       0x8000
+
+/*
+ * extattributes inode info
+ */
+#define EXT_REGULAR            0
+#define EXT_MACOSFNDRINFO      1
+#define EXT_MACOSRESFORK       2
+#define EXT_ACL                        3
+
+
+/*
+ * compression flags for the tapebuf header.
+ */
+#define COMPRESS_ZLIB  0
+#define COMPRESS_BZLIB 1
+#define COMPRESS_LZO   2
+
+/* used for compressed dump tapes */
+struct tapebuf {
+       unsigned int    compressed:1;
+       unsigned int    flags:3;
+       unsigned int    length:28;
+#ifdef sunos
+       char            buf;
+#else
+       char            buf[0]; /* the data */
+#endif
+};
+
+#endif /* !_DUMPRESTORE_H_ */
diff --git a/compat/include/rmtflags.h b/compat/include/rmtflags.h
new file mode 100644 (file)
index 0000000..a1c49fb
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: rmtflags.h,v 1.2 2003/03/30 15:40:34 stelian Exp $
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _RMTFLAGS_H_
+#define _RMTFLAGS_H_
+
+int rmtflags_toint(char *filemode);
+char *rmtflags_tochar(int filemode);
+
+#endif
diff --git a/compat/include/system.h b/compat/include/system.h
new file mode 100644 (file)
index 0000000..5ed2d27
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1980, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: system.h,v 1.3 2003/03/30 15:40:34 stelian Exp $
+ */
+
+#ifndef _SYSTEM_H_
+#define _SYSTEM_H_
+
+int system_command(const char *command, const char *device, int volnum);
+
+#endif
diff --git a/compat/lib/Makefile.in b/compat/lib/Makefile.in
new file mode 100644 (file)
index 0000000..cc90969
--- /dev/null
@@ -0,0 +1,37 @@
+# $Id: Makefile.in,v 1.10 2003/05/08 21:11:39 stelian Exp $
+
+top_srcdir=    @top_srcdir@
+srcdir=                @srcdir@
+top_builddir=  ../..
+
+@MCONFIG@
+
+INC=           -I$(top_srcdir)/compat/include
+ALL_CFLAGS=    @CPPFLAGS@ @CFLAGS@ @CCOPTS@ -pipe $(OPT) $(GINC) $(INC) $(DEFS)
+SRCS=          compaterr.c compatglob.c bylabel.c system.c rmtflags.c minilzo.c
+OBJS=          compaterr.o compatglob.o bylabel.o system.o rmtflags.o minilzo.o
+LIB=           libcompat.a
+
+.c.o:
+       $(CC) -c $(ALL_CFLAGS) $< -o $@
+
+all::          $(LIB)
+
+$(LIB):                $(OBJS)
+       $(AR) r $(LIB) $(OBJS)
+       $(RANLIB) $(LIB)
+
+install::
+
+clean::
+       $(RM) -f \#* *.s *.o *.a *~ core
+
+distclean::    clean
+       $(RM) -f Makefile Makefile.old .depend
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+
diff --git a/compat/lib/README.LZO b/compat/lib/README.LZO
new file mode 100644 (file)
index 0000000..fd1ea8a
--- /dev/null
@@ -0,0 +1,133 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+
+ ============================================================================
+ miniLZO -- mini subset of the LZO real-time data compression library
+ ============================================================================
+
+ Author  : Markus Franz Xaver Johannes Oberhumer
+           <markus@oberhumer.com>
+           http://www.oberhumer.com/opensource/lzo/
+ Version : 1.08
+ Date    : 12-Jul-2002
+
+ I've created miniLZO for projects where it is inconvenient to
+ include (or require) the full LZO source code just because you
+ want to add a little bit of data compression to your application.
+
+ miniLZO implements the LZO1X-1 compressor and both the standard and
+ safe LZO1X decompressor. Apart from fast compression it also useful
+ for situations where you want to use pre-compressed data files (which
+ must have been compressed with LZO1X-999).
+
+ miniLZO consists of one C source file and two header files:
+    minilzo.c
+    minilzo.h
+    lzoconf.h
+
+ To use miniLZO just copy these files into your source directory, add
+ minilzo.c to your Makefile and #include minilzo.h from your program.
+ Note: you also must distribute this file (`README.LZO') with your project.
+
+ minilzo.o compiles to about 6 kB (using gcc or Visual C on a i386), and
+ the sources are about 14 kB when packed with zip - so there's no more
+ excuse that your application doesn't support data compression :-)
+
+ For more information, documentation, example programs and other support
+ files (like Makefiles and build scripts) please download the full LZO
+ package from
+    http://www.oberhumer.com/opensource/lzo/
+
+ Have fun,
+  Markus
+
+
+ P.S. minilzo.c is generated automatically from the LZO sources and
+      therefore functionality is completely identical
+
+
+ Appendix A: building miniLZO
+ ----------------------------
+ miniLZO is written such a way that it should compile and run
+ out-of-the-box on most machines.
+
+ If you are running on a very unusual architecture and lzo_init() fails then
+ you should first recompile with `-DLZO_DEBUG' to see what causes the failure.
+ The most probable case is something like `sizeof(char *) != sizeof(long)'.
+ After identifying the problem you can compile by adding some defines
+ like `-DSIZEOF_CHAR_P=8' to your Makefile.
+
+ The best solution is (of course) using Autoconf - if your project uses
+ Autoconf anyway just add `-DMINILZO_HAVE_CONFIG_H' to your compiler
+ flags when compiling minilzo.c. See the LZO distribution for an example
+ how to set up configure.in.
+
+
+ Appendix B: list of public functions available in miniLZO
+ ---------------------------------------------------------
+ Library initialization
+    lzo_init()
+
+ Compression
+    lzo1x_1_compress()
+
+ Decompression
+    lzo1x_decompress()
+    lzo1x_decompress_safe()
+
+ Checksum functions
+    lzo_adler32()
+
+ Version functions
+    lzo_version()
+    lzo_version_string()
+    lzo_version_date()
+
+ Portable (but slow) string functions
+    lzo_memcmp()
+    lzo_memcpy()
+    lzo_memmove()
+    lzo_memset()
+
+
+ Appendix C: suggested macros for `configure.in' when using Autoconf
+ -------------------------------------------------------------------
+ Checks for typedefs and structures
+    AC_CHECK_TYPE(ptrdiff_t,long)
+    AC_TYPE_SIZE_T
+    AC_CHECK_SIZEOF(unsigned short)
+    AC_CHECK_SIZEOF(unsigned)
+    AC_CHECK_SIZEOF(unsigned long)
+    AC_CHECK_SIZEOF(char *)
+    AC_CHECK_SIZEOF(ptrdiff_t)
+    AC_CHECK_SIZEOF(size_t)
+
+ Checks for compiler characteristics
+    AC_C_CONST
+
+ Checks for library functions
+    AC_CHECK_FUNCS(memcmp memcpy memmove memset)
+
+
+ Appendix D: Copyright
+ ---------------------
+ LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
+ Markus Franz Xaver Johannes Oberhumer
+
+ LZO and miniLZO are distributed under the terms of the GNU General
+ Public License (GPL).  See the file COPYING.
+
+ Special licenses for commercial and other applications which
+ are not willing to accept the GNU General Public License
+ are available by contacting the author.
+
+
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.0.7 (GNU/Linux)
+
+iD8DBQE9LPb4TWFXqwsgQ8kRAi/wAKCZ9Iej+voGhmKATaViOPS9chxGUwCgh5Dk
+uwMS2PQ7BXHT0vf4yz+3tTc=
+=PsNp
+-----END PGP SIGNATURE-----
diff --git a/compat/lib/README2.LZO b/compat/lib/README2.LZO
new file mode 100644 (file)
index 0000000..b27597c
--- /dev/null
@@ -0,0 +1,10 @@
+The copyright notice in appendix D of the file README.LZO fully applies.
+
+Hereby I grant a special license to the "Dump/restore utilities" project
+(currently hosted at http://dump.sourceforge.net ) to integrate the
+minilzo project (currently version 1.08 hosted at 
+http://www.oberhumer.com/opensource/lzo) in source form. Both files, 
+README.LZO and README2.LZO, must be distributed with the source of the 
+"Dump/restore utilities".
+
+Markus Oberhumer, <markus@oberhumer.com>, http://www.oberhumer.com/        
diff --git a/compat/lib/bylabel.c b/compat/lib/bylabel.c
new file mode 100644 (file)
index 0000000..5a40a70
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * mount_by_label.c - aeb
+ *
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ * 2000-01-20 James Antill <james@and.org>
+ * - Added error message if /proc/partitions cannot be opened
+ * 2000-05-09 Erik Troan <ewt@redhat.com>
+ * - Added cache for UUID and disk labels
+ * Wed Aug 16 2000 Erik Troan <ewt@redhat.com>
+ * - Ported to dump/restore
+ */
+
+#include <config.h>
+#include <compatlfs.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <sys/cdefs.h>
+#include "bylabel.h"
+
+#ifndef HAVE_BLKID
+
+#define PROC_PARTITIONS "/proc/partitions"
+#define DEVLABELDIR    "/dev"
+
+#define EXT2_SUPER_OFFSET      1024
+#define EXT2_SUPER_SIZE                sizeof(struct ext2_super_block)
+#define EXT2_SUPER_MAGIC       0xEF53
+
+#define VOLNAMSZ       16
+
+struct ext2_super_block {
+       unsigned char   s_dummy1[56];
+       unsigned char   s_magic[2];
+       unsigned char   s_dummy2[46];
+       unsigned char   s_uuid[16];
+       unsigned char   s_volume_name[VOLNAMSZ];
+};
+#define ext2magic(s)   ((unsigned int) s.s_magic[0] + (((unsigned int) s.s_magic[1]) << 8))
+
+void msg __P((const char *fmt, ...));
+
+static struct uuidCache_s {
+       struct uuidCache_s *next;
+       char uuid[16];
+       char *label;
+       char *device;
+} *uuidCache = NULL;
+
+/* for now, only ext2 is supported */
+static int
+get_label_uuid(const char *device, char **label, char *uuid) {
+
+       /* start with a test for ext2, taken from mount_guess_fstype */
+       /* should merge these later */
+       int fd;
+       struct ext2_super_block e2sb;
+
+       fd = OPEN(device, O_RDONLY);
+       if (fd < 0)
+               return 1;
+
+       if (LSEEK(fd, EXT2_SUPER_OFFSET, SEEK_SET) != EXT2_SUPER_OFFSET ||
+           read(fd, (char *) &e2sb, EXT2_SUPER_SIZE) != EXT2_SUPER_SIZE ||
+           ext2magic(e2sb) != EXT2_SUPER_MAGIC) {
+               close(fd);
+               return 1;
+       }
+
+       close(fd);
+
+       /* superblock is ext2 - now what is its label? */
+       memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
+       *label = malloc(VOLNAMSZ + 1);
+       strncpy(*label, e2sb.s_volume_name, VOLNAMSZ);
+       (*label)[VOLNAMSZ] = 0;
+
+       return 0;
+}
+
+static void
+uuidcache_addentry(char *device, char *label, char *uuid) {
+       struct uuidCache_s *last;
+
+       if (!uuidCache) {
+               last = uuidCache = (struct uuidCache_s *)malloc(sizeof(*uuidCache));
+       } else {
+               for (last = uuidCache; last->next; last = last->next) ;
+               last->next = (struct uuidCache_s *)malloc(sizeof(*uuidCache));
+               last = last->next;
+       }
+       last->next = NULL;
+       last->device = device;
+       last->label = label;
+       memcpy(last->uuid, uuid, sizeof(last->uuid));
+}
+
+static void
+uuidcache_init(void) {
+       char line[100];
+       char *s;
+       int ma, mi, sz;
+       static char ptname[100];
+       FILE *procpt;
+       char uuid[16], *label;
+       char device[110];
+       int firstPass;
+       int handleOnFirst;
+
+       if (uuidCache)
+               return;
+
+       procpt = fopen(PROC_PARTITIONS, "r");
+       if (!procpt)
+               return;
+
+       for (firstPass = 1; firstPass >= 0; firstPass--) {
+           fseek(procpt, 0, SEEK_SET);
+
+           while (fgets(line, sizeof(line), procpt)) {
+               if (sscanf (line, " %d %d %d %[^\n ]",
+                           &ma, &mi, &sz, ptname) != 4)
+                       continue;
+
+               /* skip extended partitions (heuristic: size 1) */
+               if (sz == 1)
+                       continue;
+
+               /* look only at md devices on first pass */
+               handleOnFirst = !strncmp(ptname, "md", 2);
+               if (firstPass != handleOnFirst)
+                       continue;
+
+               /* skip entire disk (minor 0, 64, ... on ide;
+                  0, 16, ... on sd) */
+               /* heuristic: partition name ends in a digit */
+
+               for(s = ptname; *s; s++);
+               if (isdigit(s[-1])) {
+               /*
+                * Note: this is a heuristic only - there is no reason
+                * why these devices should live in /dev.
+                * Perhaps this directory should be specifiable by option.
+                * One might for example have /devlabel with links to /dev
+                * for the devices that may be accessed in this way.
+                * (This is useful, if the cdrom on /dev/hdc must not
+                * be accessed.)
+                */
+                       sprintf(device, "%s/%s", DEVLABELDIR, ptname);
+                       if (!get_label_uuid(device, &label, uuid))
+                               uuidcache_addentry(strdup(device), label, uuid);
+               }
+           }
+       }
+
+       fclose(procpt);
+}
+
+#define UUID   1
+#define VOL    2
+
+static char *
+get_spec_by_x(int n, const char *t) {
+       struct uuidCache_s *uc;
+
+       uuidcache_init();
+       uc = uuidCache;
+
+       while(uc) {
+               switch (n) {
+               case UUID:
+                       if (!memcmp(t, uc->uuid, sizeof(uc->uuid)))
+                               return strdup(uc->device);
+                       break;
+               case VOL:
+                       if (!strcmp(t, uc->label))
+                               return strdup(uc->device);
+                       break;
+               }
+               uc = uc->next;
+       }
+       return NULL;
+}
+
+static u_char
+fromhex(char c) {
+       if (isdigit(c))
+               return (c - '0');
+       else if (islower(c))
+               return (c - 'a' + 10);
+       else
+               return (c - 'A' + 10);
+}
+
+static char *
+get_spec_by_uuid(const char *s) {
+       u_char uuid[16];
+       int i;
+
+       if (strlen(s) != 36 ||
+           s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
+               goto bad_uuid;
+       for (i=0; i<16; i++) {
+           if (*s == '-') s++;
+           if (!isxdigit(s[0]) || !isxdigit(s[1]))
+                   goto bad_uuid;
+           uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
+           s += 2;
+       }
+       return get_spec_by_x(UUID, uuid);
+
+ bad_uuid:
+       msg("mount: bad UUID\n");
+       return NULL;            /* just for gcc */
+}
+
+static char *
+get_spec_by_volume_label(const char *s) {
+       return get_spec_by_x(VOL, s);
+}
+
+const char * 
+get_device_name(const char * item) {
+       const char * rc;
+
+       if (!strncmp(item, "UUID=", 5)) {
+               rc = get_spec_by_uuid(item+5);
+       } 
+       else
+               if (!strncmp(item, "LABEL=", 6)) {
+                       rc = get_spec_by_volume_label(item+6);
+               }
+               else {
+                       rc = item;
+               }
+
+       return rc;
+}
+
+const char *
+get_device_label(const char * spec) {
+       struct uuidCache_s *uc;
+
+       uuidcache_init();
+       uc = uuidCache;
+
+       while(uc) {
+               if (!strcmp(spec, uc->device))
+                       return uc->label[0] == '\0' ? NULL : strdup(uc->label);
+               uc = uc->next;
+       }
+       return NULL;
+}
+
+#endif /* !HAVE_BLKID */
diff --git a/compat/lib/compaterr.c b/compat/lib/compaterr.c
new file mode 100644 (file)
index 0000000..8ae4686
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: compaterr.c,v 1.11 2003/10/26 16:05:46 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <sys/types.h>
+#include <compaterr.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+extern char *__progname;               /* Program name, from crt0. */
+
+#if !defined(HAVE_ERR) || !defined(HAVE_ERRX) || !defined(HAVE_VERR) || !defined(HAVE_VERRX) || !defined(HAVE_VWARN) || !defined(HAVE_VWARNX) || !defined(HAVE_WARN) || !defined(HAVE_WARNX)
+
+__BEGIN_DECLS
+__dead void     errc __P((int, int, const char *, ...));
+__dead void     verrc __P((int, int, const char *, _BSD_VA_LIST_));
+void            warnc __P((int, const char *, ...));
+void            vwarnc __P((int, const char *, _BSD_VA_LIST_));
+void            err_set_file __P((void *));
+void            err_set_exit __P((void (*)(int)));
+__END_DECLS
+
+static void (*err_exit)(int);
+
+static FILE *err_file; /* file to use for error output */
+/*
+ * This is declared to take a `void *' so that the caller is not required
+ * to include <stdio.h> first.  However, it is really a `FILE *', and the
+ * manual page documents it as such.
+ */
+void
+err_set_file(void *fp)
+{
+       if (fp)
+               err_file = fp;
+       else
+               err_file = stderr;
+}
+
+void
+err_set_exit(void (*ef)(int))
+{
+       err_exit = ef;
+}
+
+__dead void
+errc(int eval, int code, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       verrc(eval, code, fmt, ap);
+       va_end(ap);
+}
+
+__dead void
+verrc(int eval, int code, const char *fmt, va_list ap)
+{
+       if (err_file == 0)
+               err_set_file((FILE *)0);
+       fprintf(err_file, "%s: ", __progname);
+       if (fmt != NULL) {
+               vfprintf(err_file, fmt, ap);
+               fprintf(err_file, ": ");
+       }
+       fprintf(err_file, "%s\n", strerror(code));
+       if (err_exit)
+               err_exit(eval);
+       exit(eval);
+}
+
+void
+warnc(int code, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       vwarnc(code, fmt, ap);
+       va_end(ap);
+}
+
+void
+vwarnc(int code, const char *fmt, va_list ap)
+{
+       if (err_file == 0)
+               err_set_file((FILE *)0);
+       fprintf(err_file, "%s: ", __progname);
+       if (fmt != NULL) {
+               vfprintf(err_file, fmt, ap);
+               fprintf(err_file, ": ");
+       }
+       fprintf(err_file, "%s\n", strerror(code));
+}
+#endif
+
+#ifndef        HAVE_ERR
+__dead void
+err(int eval, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       verrc(eval, errno, fmt, ap);
+       va_end(ap);
+}
+#endif
+
+#ifndef        HAVE_VERR
+__dead void
+verr(int eval, const char *fmt, va_list ap)
+{
+       verrc(eval, errno, fmt, ap);
+}
+#endif
+
+#ifndef        HAVE_ERRX
+__dead void
+errx(int eval, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       verrx(eval, fmt, ap);
+       va_end(ap);
+}
+#endif
+
+#ifndef        HAVE_VERRX
+__dead void
+verrx(int eval, const char *fmt, va_list ap)
+{
+       if (err_file == 0)
+               err_set_file((FILE *)0);
+       fprintf(err_file, "%s: ", __progname);
+       if (fmt != NULL)
+               vfprintf(err_file, fmt, ap);
+       fprintf(err_file, "\n");
+       if (err_exit)
+               err_exit(eval);
+       exit(eval);
+}
+#endif
+
+#ifndef        HAVE_WARN
+void
+warn(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       vwarnc(errno, fmt, ap);
+       va_end(ap);
+}
+#endif
+
+#ifndef        HAVE_VWARN
+void
+vwarn(const char *fmt, va_list ap)
+{
+       vwarnc(errno, fmt, ap);
+}
+#endif
+
+#ifndef        HAVE_WARNX
+void
+warnx(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       vwarnx(fmt, ap);
+       va_end(ap);
+}
+#endif
+
+#ifndef        HAVE_VWARNX
+void
+vwarnx(const char *fmt, va_list ap)
+{
+       if (err_file == 0)
+               err_set_file((FILE *)0);
+       fprintf(err_file, "%s: ", __progname);
+       if (fmt != NULL)
+               vfprintf(err_file, fmt, ap);
+       fprintf(err_file, "\n");
+}
+#endif
diff --git a/compat/lib/compatglob.c b/compat/lib/compatglob.c
new file mode 100644 (file)
index 0000000..8cf77ea
--- /dev/null
@@ -0,0 +1,831 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * glob(3) -- a superset of the one defined in POSIX 1003.2.
+ *
+ * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
+ *
+ * Optional extra services, controlled by flags not defined by POSIX:
+ *
+ * GLOB_QUOTE:
+ *     Escaping convention: \ inhibits any special meaning the following
+ *     character might have (except \ at end of string is retained).
+ * GLOB_MAGCHAR:
+ *     Set in gl_flags if pattern contained a globbing character.
+ * GLOB_NOMAGIC:
+ *     Same as GLOB_NOCHECK, but it will only append pattern if it did
+ *     not contain any magic characters.  [Used in csh style globbing]
+ * GLOB_ALTDIRFUNC:
+ *     Use alternately specified directory access functions.
+ * GLOB_TILDE:
+ *     expand ~user/foo to the /home/dir/of/user/foo
+ * GLOB_BRACE:
+ *     expand {1,2}{a,b} to 1a 1b 2a 2b
+ * gl_matchc:
+ *     Number of matches in the current invocation of glob.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: compatglob.c,v 1.10 2003/10/26 16:05:46 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <sys/types.h>
+
+#ifndef HAVE_GLOB
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <compatglob.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define        DOLLAR          '$'
+#define        DOT             '.'
+#define        EOS             '\0'
+#define        LBRACKET        '['
+#define        NOT             '!'
+#define        QUESTION        '?'
+#define        QUOTE           '\\'
+#define        RANGE           '-'
+#define        RBRACKET        ']'
+#define        SEP             '/'
+#define        STAR            '*'
+#define        TILDE           '~'
+#define        UNDERSCORE      '_'
+#define        LBRACE          '{'
+#define        RBRACE          '}'
+#define        SLASH           '/'
+#define        COMMA           ','
+
+#ifndef DEBUG
+
+#define        M_QUOTE         0x8000
+#define        M_PROTECT       0x4000
+#define        M_MASK          0xffff
+#define        M_ASCII         0x00ff
+
+typedef u_short Char;
+
+#else
+
+#define        M_QUOTE         0x80
+#define        M_PROTECT       0x40
+#define        M_MASK          0xff
+#define        M_ASCII         0x7f
+
+typedef char Char;
+
+#endif
+
+
+#define        CHAR(c)         ((Char)((c)&M_ASCII))
+#define        META(c)         ((Char)((c)|M_QUOTE))
+#define        M_ALL           META('*')
+#define        M_END           META(']')
+#define        M_NOT           META('!')
+#define        M_ONE           META('?')
+#define        M_RNG           META('-')
+#define        M_SET           META('[')
+#define        ismeta(c)       (((c)&M_QUOTE) != 0)
+
+
+static int      compare __P((const void *, const void *));
+static void     g_Ctoc __P((const Char *, char *));
+static int      g_lstat __P((Char *, struct stat *, glob_t *));
+static DIR     *g_opendir __P((Char *, glob_t *));
+static Char    *g_strchr __P((Char *, int));
+#ifdef notdef
+static Char    *g_strcat __P((Char *, const Char *));
+#endif
+static int      g_stat __P((Char *, struct stat *, glob_t *));
+static int      glob0 __P((const Char *, glob_t *));
+static int      glob1 __P((Char *, glob_t *));
+static int      glob2 __P((Char *, Char *, Char *, glob_t *));
+static int      glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
+static int      globextend __P((const Char *, glob_t *));
+static const Char *     globtilde __P((const Char *, Char *, size_t, glob_t *));
+static int      globexp1 __P((const Char *, glob_t *));
+static int      globexp2 __P((const Char *, const Char *, glob_t *, int *));
+static int      match __P((Char *, Char *, Char *));
+#ifdef DEBUG
+static void     qprintf __P((const char *, Char *));
+#endif
+
+int
+glob(const char *pattern, int flags, int (*errfunc) __P((const char *, int)), glob_t *pglob)
+{
+       const u_char *patnext;
+       int c;
+       Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
+
+       patnext = (u_char *) pattern;
+       if (!(flags & GLOB_APPEND)) {
+               pglob->gl_pathc = 0;
+               pglob->gl_pathv = NULL;
+               if (!(flags & GLOB_DOOFFS))
+                       pglob->gl_offs = 0;
+       }
+       pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+       pglob->gl_errfunc = errfunc;
+       pglob->gl_matchc = 0;
+
+       bufnext = patbuf;
+       bufend = bufnext + MAXPATHLEN;
+       if (flags & GLOB_QUOTE) {
+               /* Protect the quoted characters. */
+               while (bufnext < bufend && (c = *patnext++) != EOS)
+                       if (c == QUOTE) {
+                               if ((c = *patnext++) == EOS) {
+                                       c = QUOTE;
+                                       --patnext;
+                               }
+                               *bufnext++ = c | M_PROTECT;
+                       }
+                       else
+                               *bufnext++ = c;
+       }
+       else
+           while (bufnext < bufend && (c = *patnext++) != EOS)
+                   *bufnext++ = c;
+       *bufnext = EOS;
+
+       if (flags & GLOB_BRACE)
+           return globexp1(patbuf, pglob);
+       else
+           return glob0(patbuf, pglob);
+}
+
+/*
+ * Expand recursively a glob {} pattern. When there is no more expansion
+ * invoke the standard globbing routine to glob the rest of the magic
+ * characters
+ */
+static int globexp1(const Char *pattern, glob_t *pglob)
+{
+       const Char* ptr = pattern;
+       int rv;
+
+       /* Protect a single {}, for find(1), like csh */
+       if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
+               return glob0(pattern, pglob);
+
+       while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
+               if (!globexp2(ptr, pattern, pglob, &rv))
+                       return rv;
+
+       return glob0(pattern, pglob);
+}
+
+
+/*
+ * Recursive brace globbing helper. Tries to expand a single brace.
+ * If it succeeds then it invokes globexp1 with the new pattern.
+ * If it fails then it tries to glob the rest of the pattern and returns.
+ */
+static int globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)
+{
+       int     i;
+       Char   *lm, *ls;
+       const Char *pe, *pm, *pl;
+       Char    patbuf[MAXPATHLEN + 1];
+
+       /* copy part up to the brace */
+       for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
+               continue;
+       ls = lm;
+
+       /* Find the balanced brace */
+       for (i = 0, pe = ++ptr; *pe; pe++)
+               if (*pe == LBRACKET) {
+                       /* Ignore everything between [] */
+                       for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
+                               continue;
+                       if (*pe == EOS) {
+                               /*
+                                * We could not find a matching RBRACKET.
+                                * Ignore and just look for RBRACE
+                                */
+                               pe = pm;
+                       }
+               }
+               else if (*pe == LBRACE)
+                       i++;
+               else if (*pe == RBRACE) {
+                       if (i == 0)
+                               break;
+                       i--;
+               }
+
+       /* Non matching braces; just glob the pattern */
+       if (i != 0 || *pe == EOS) {
+               *rv = glob0(patbuf, pglob);
+               return 0;
+       }
+
+       for (i = 0, pl = pm = ptr; pm <= pe; pm++)
+               switch (*pm) {
+               case LBRACKET:
+                       /* Ignore everything between [] */
+                       for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
+                               continue;
+                       if (*pm == EOS) {
+                               /*
+                                * We could not find a matching RBRACKET.
+                                * Ignore and just look for RBRACE
+                                */
+                               pm = pl;
+                       }
+                       break;
+
+               case LBRACE:
+                       i++;
+                       break;
+
+               case RBRACE:
+                       if (i) {
+                           i--;
+                           break;
+                       }
+                       /* FALLTHROUGH */
+               case COMMA:
+                       if (i && *pm == COMMA)
+                               break;
+                       else {
+                               /* Append the current string */
+                               for (lm = ls; (pl < pm); *lm++ = *pl++)
+                                       continue;
+                               /*
+                                * Append the rest of the pattern after the
+                                * closing brace
+                                */
+                               for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
+                                       continue;
+
+                               /* Expand the current pattern */
+#ifdef DEBUG
+                               qprintf("globexp2:", patbuf);
+#endif
+                               *rv = globexp1(patbuf, pglob);
+
+                               /* move after the comma, to the next string */
+                               pl = pm + 1;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       *rv = 0;
+       return 0;
+}
+
+
+
+/*
+ * expand tilde from the passwd file.
+ */
+static const Char *
+globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
+{
+       struct passwd *pwd;
+       char *h;
+       const Char *p;
+       Char *b, *eb;
+
+       if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
+               return pattern;
+
+       /* 
+        * Copy up to the end of the string or / 
+        */
+       eb = &patbuf[patbuf_len - 1];
+       for (p = pattern + 1, h = (char *) patbuf;
+           h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
+               continue;
+
+       *h = EOS;
+
+       if (((char *) patbuf)[0] == EOS) {
+               /*
+                * handle a plain ~ or ~/ by expanding $HOME first if
+                * we're not running setuid or setgid) and then trying
+                * the password file
+                */
+               if (
+#if !defined(__linux__) && !defined(sunos)
+#ifndef        __NETBSD_SYSCALLS
+                   issetugid() != 0 ||
+#endif
+#endif
+                   (h = getenv("HOME")) == NULL) {
+                       if (((h = getlogin()) != NULL &&
+                            (pwd = getpwnam(h)) != NULL) ||
+                           (pwd = getpwuid(getuid())) != NULL)
+                               h = pwd->pw_dir;
+                       else
+                               return pattern;
+               }
+       }
+       else {
+               /*
+                * Expand a ~user
+                */
+               if ((pwd = getpwnam((char*) patbuf)) == NULL)
+                       return pattern;
+               else
+                       h = pwd->pw_dir;
+       }
+
+       /* Copy the home directory */
+       for (b = patbuf; b < eb && *h; *b++ = *h++)
+               continue;
+
+       /* Append the rest of the pattern */
+       while (b < eb && (*b++ = *p++) != EOS)
+               continue;
+       *b = EOS;
+
+       return patbuf;
+}
+
+
+/*
+ * The main glob() routine: compiles the pattern (optionally processing
+ * quotes), calls glob1() to do the real pattern matching, and finally
+ * sorts the list (unless unsorted operation is requested).  Returns 0
+ * if things went well, nonzero if errors occurred.  It is not an error
+ * to find no matches.
+ */
+static int
+glob0(const Char *pattern, glob_t *pglob)
+{
+       const Char *qpatnext;
+       int c, err, oldpathc;
+       Char *bufnext, patbuf[MAXPATHLEN+1];
+
+       qpatnext = globtilde(pattern, patbuf, sizeof(patbuf) / sizeof(Char), 
+           pglob);
+       oldpathc = pglob->gl_pathc;
+       bufnext = patbuf;
+
+       /* We don't need to check for buffer overflow any more. */
+       while ((c = *qpatnext++) != EOS) {
+               switch (c) {
+               case LBRACKET:
+                       c = *qpatnext;
+                       if (c == NOT)
+                               ++qpatnext;
+                       if (*qpatnext == EOS ||
+                           g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
+                               *bufnext++ = LBRACKET;
+                               if (c == NOT)
+                                       --qpatnext;
+                               break;
+                       }
+                       *bufnext++ = M_SET;
+                       if (c == NOT)
+                               *bufnext++ = M_NOT;
+                       c = *qpatnext++;
+                       do {
+                               *bufnext++ = CHAR(c);
+                               if (*qpatnext == RANGE &&
+                                   (c = qpatnext[1]) != RBRACKET) {
+                                       *bufnext++ = M_RNG;
+                                       *bufnext++ = CHAR(c);
+                                       qpatnext += 2;
+                               }
+                       } while ((c = *qpatnext++) != RBRACKET);
+                       pglob->gl_flags |= GLOB_MAGCHAR;
+                       *bufnext++ = M_END;
+                       break;
+               case QUESTION:
+                       pglob->gl_flags |= GLOB_MAGCHAR;
+                       *bufnext++ = M_ONE;
+                       break;
+               case STAR:
+                       pglob->gl_flags |= GLOB_MAGCHAR;
+                       /* collapse adjacent stars to one,
+                        * to avoid exponential behavior
+                        */
+                       if (bufnext == patbuf || bufnext[-1] != M_ALL)
+                           *bufnext++ = M_ALL;
+                       break;
+               default:
+                       *bufnext++ = CHAR(c);
+                       break;
+               }
+       }
+       *bufnext = EOS;
+#ifdef DEBUG
+       qprintf("glob0:", patbuf);
+#endif
+
+       if ((err = glob1(patbuf, pglob)) != 0)
+               return(err);
+
+       /*
+        * If there was no match we are going to append the pattern
+        * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+        * and the pattern did not contain any magic characters
+        * GLOB_NOMAGIC is there just for compatibility with csh.
+        */
+       if (pglob->gl_pathc == oldpathc &&
+           ((pglob->gl_flags & GLOB_NOCHECK) ||
+             ((pglob->gl_flags & GLOB_NOMAGIC) &&
+              !(pglob->gl_flags & GLOB_MAGCHAR))))
+               return(globextend(pattern, pglob));
+       else if (!(pglob->gl_flags & GLOB_NOSORT))
+               qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
+                   pglob->gl_pathc - oldpathc, sizeof(char *), compare);
+       return(0);
+}
+
+static int
+compare(const void *p, const void *q)
+{
+       return(strcmp(*(char **)p, *(char **)q));
+}
+
+static int
+glob1(Char *pattern, glob_t *pglob)
+{
+       Char pathbuf[MAXPATHLEN+1];
+
+       /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+       if (*pattern == EOS)
+               return(0);
+       return(glob2(pathbuf, pathbuf, pattern, pglob));
+}
+
+/*
+ * The functions glob2 and glob3 are mutually recursive; there is one level
+ * of recursion for each segment in the pattern that contains one or more
+ * meta characters.
+ */
+static int
+glob2(Char *pathbuf, Char *pathend, Char *pattern, glob_t *pglob)
+{
+       struct stat sb;
+       Char *p, *q;
+       int anymeta;
+
+       /*
+        * Loop over pattern segments until end of pattern or until
+        * segment with meta character found.
+        */
+       for (anymeta = 0;;) {
+               if (*pattern == EOS) {          /* End of pattern? */
+                       *pathend = EOS;
+                       if (g_lstat(pathbuf, &sb, pglob))
+                               return(0);
+
+                       if (((pglob->gl_flags & GLOB_MARK) &&
+                           pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
+                           || (S_ISLNK(sb.st_mode) &&
+                           (g_stat(pathbuf, &sb, pglob) == 0) &&
+                           S_ISDIR(sb.st_mode)))) {
+                               *pathend++ = SEP;
+                               *pathend = EOS;
+                       }
+                       ++pglob->gl_matchc;
+                       return(globextend(pathbuf, pglob));
+               }
+
+               /* Find end of next segment, copy tentatively to pathend. */
+               q = pathend;
+               p = pattern;
+               while (*p != EOS && *p != SEP) {
+                       if (ismeta(*p))
+                               anymeta = 1;
+                       *q++ = *p++;
+               }
+
+               if (!anymeta) {         /* No expansion, do next segment. */
+                       pathend = q;
+                       pattern = p;
+                       while (*pattern == SEP)
+                               *pathend++ = *pattern++;
+               } else                  /* Need expansion, recurse. */
+                       return(glob3(pathbuf, pathend, pattern, p, pglob));
+       }
+       /* NOTREACHED */
+}
+
+static int
+glob3(Char *pathbuf, Char *pathend, Char *pattern, Char *restpattern, glob_t *pglob)
+{
+       struct dirent *dp;
+       DIR *dirp;
+       int err;
+       char buf[MAXPATHLEN];
+
+       /*
+        * The readdirfunc declaration can't be prototyped, because it is
+        * assigned, below, to two functions which are prototyped in glob.h
+        * and dirent.h as taking pointers to differently typed opaque
+        * structures.
+        */
+       struct dirent *(*readdirfunc)();
+
+       *pathend = EOS;
+       errno = 0;
+
+       if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
+               /* TODO: don't call for ENOENT or ENOTDIR? */
+               if (pglob->gl_errfunc) {
+                       g_Ctoc(pathbuf, buf);
+                       if (pglob->gl_errfunc(buf, errno) ||
+                           pglob->gl_flags & GLOB_ERR)
+                               return (GLOB_ABEND);
+               }
+               return(0);
+       }
+
+       err = 0;
+
+       /* Search directory for matching names. */
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               readdirfunc = pglob->gl_readdir;
+       else
+               readdirfunc = readdir;
+       while ((dp = (*readdirfunc)(dirp))) {
+               u_char *sc;
+               Char *dc;
+
+               /* Initial DOT must be matched literally. */
+               if (dp->d_name[0] == DOT && *pattern != DOT)
+                       continue;
+               for (sc = (u_char *) dp->d_name, dc = pathend;
+                    (*dc++ = *sc++) != EOS;)
+                       continue;
+               if (!match(pathend, pattern, restpattern)) {
+                       *pathend = EOS;
+                       continue;
+               }
+               err = glob2(pathbuf, --dc, restpattern, pglob);
+               if (err)
+                       break;
+       }
+
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               (*pglob->gl_closedir)(dirp);
+       else
+               closedir(dirp);
+       return(err);
+}
+
+
+/*
+ * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
+ * add the new item, and update gl_pathc.
+ *
+ * This assumes the BSD realloc, which only copies the block when its size
+ * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
+ * behavior.
+ *
+ * Return 0 if new item added, error code if memory couldn't be allocated.
+ *
+ * Invariant of the glob_t structure:
+ *     Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
+ *     gl_pathv points to (gl_offs + gl_pathc + 1) items.
+ */
+static int
+globextend(const Char *path, glob_t *pglob)
+{
+       char **pathv;
+       int i;
+       u_int newsize;
+       char *copy;
+       const Char *p;
+
+       newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+       pathv = pglob->gl_pathv ?
+                   realloc((char *)pglob->gl_pathv, newsize) :
+                   malloc(newsize);
+       if (pathv == NULL)
+               return(GLOB_NOSPACE);
+
+       if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
+               /* first time around -- clear initial gl_offs items */
+               pathv += pglob->gl_offs;
+               for (i = pglob->gl_offs; --i >= 0; )
+                       *--pathv = NULL;
+       }
+       pglob->gl_pathv = pathv;
+
+       for (p = path; *p++;)
+               continue;
+       if ((copy = malloc(p - path)) != NULL) {
+               g_Ctoc(path, copy);
+               pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
+       }
+       pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+       return(copy == NULL ? GLOB_NOSPACE : 0);
+}
+
+/*
+ * pattern matching function for filenames.  Each occurrence of the *
+ * pattern causes a recursion level.
+ */
+static int
+match(Char *name, Char *pat, Char *patend)
+{
+       int ok, negate_range;
+       Char c, k;
+
+       while (pat < patend) {
+               c = *pat++;
+               switch (c & M_MASK) {
+               case M_ALL:
+                       if (pat == patend)
+                               return(1);
+                       do
+                           if (match(name, pat, patend))
+                                   return(1);
+                       while (*name++ != EOS);
+                       return(0);
+               case M_ONE:
+                       if (*name++ == EOS)
+                               return(0);
+                       break;
+               case M_SET:
+                       ok = 0;
+                       if ((k = *name++) == EOS)
+                               return(0);
+                       if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
+                               ++pat;
+                       while (((c = *pat++) & M_MASK) != M_END)
+                               if ((*pat & M_MASK) == M_RNG) {
+                                       if (c <= k && k <= pat[1])
+                                               ok = 1;
+                                       pat += 2;
+                               } else if (c == k)
+                                       ok = 1;
+                       if (ok == negate_range)
+                               return(0);
+                       break;
+               default:
+                       if (*name++ != c)
+                               return(0);
+                       break;
+               }
+       }
+       return(*name == EOS);
+}
+
+/* Free allocated data belonging to a glob_t structure. */
+void
+globfree(glob_t *pglob)
+{
+       int i;
+       char **pp;
+
+       if (pglob->gl_pathv != NULL) {
+               pp = pglob->gl_pathv + pglob->gl_offs;
+               for (i = pglob->gl_pathc; i--; ++pp)
+                       if (*pp)
+                               free(*pp);
+               free(pglob->gl_pathv);
+       }
+}
+
+static DIR *
+g_opendir(Char *str, glob_t *pglob)
+{
+       char buf[MAXPATHLEN];
+
+       if (!*str)
+               strcpy(buf, ".");
+       else
+               g_Ctoc(str, buf);
+
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               return((*pglob->gl_opendir)(buf));
+
+       return(opendir(buf));
+}
+
+static int
+g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
+{
+       char buf[MAXPATHLEN];
+
+       g_Ctoc(fn, buf);
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               return((*pglob->gl_lstat)(buf, sb));
+       return(lstat(buf, sb));
+}
+
+static int
+g_stat(Char *fn, struct stat *sb, glob_t *pglob)
+{
+       char buf[MAXPATHLEN];
+
+       g_Ctoc(fn, buf);
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               return((*pglob->gl_stat)(buf, sb));
+       return(stat(buf, sb));
+}
+
+static Char *
+g_strchr(Char *str, int ch)
+{
+       do {
+               if (*str == ch)
+                       return (str);
+       } while (*str++);
+       return (NULL);
+}
+
+#ifdef notdef
+static Char *
+g_strcat(Char *dst, const Char *src)
+{
+       Char *sdst = dst;
+
+       while (*dst++)
+               continue;
+       --dst;
+       while((*dst++ = *src++) != EOS)
+           continue;
+
+       return (sdst);
+}
+#endif
+
+static void
+g_Ctoc(const Char *str, char *buf)
+{
+       char *dc;
+
+       for (dc = buf; (*dc++ = *str++) != EOS;)
+               continue;
+}
+
+#ifdef DEBUG
+static void
+qprintf(const char *str, Char *s)
+{
+       Char *p;
+
+       (void)printf("%s:\n", str);
+       for (p = s; *p; p++)
+               (void)printf("%c", CHAR(*p));
+       (void)printf("\n");
+       for (p = s; *p; p++)
+               (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
+       (void)printf("\n");
+       for (p = s; *p; p++)
+               (void)printf("%c", ismeta(*p) ? '_' : ' ');
+       (void)printf("\n");
+}
+#endif
+
+#endif /* ! HAVE_GLOB */
diff --git a/compat/lib/minilzo.c b/compat/lib/minilzo.c
new file mode 100644 (file)
index 0000000..85771eb
--- /dev/null
@@ -0,0 +1,2935 @@
+/* minilzo.c -- mini subset of the LZO real-time data compression library
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+ */
+
+/*
+ * NOTE:
+ *   the full LZO package can be found at
+ *   http://www.oberhumer.com/opensource/lzo/
+ */
+
+#define __LZO_IN_MINILZO
+#define LZO_BUILD
+
+#ifdef MINILZO_HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "minilzo.h"
+
+#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x1080)
+#  error "version mismatch in miniLZO source files"
+#endif
+
+#ifdef MINILZO_HAVE_CONFIG_H
+#  define LZO_HAVE_CONFIG_H
+#endif
+
+#if !defined(LZO_NO_SYS_TYPES_H)
+#  include <sys/types.h>
+#endif
+#include <stdio.h>
+
+#ifndef __LZO_CONF_H
+#define __LZO_CONF_H
+
+#if !defined(__LZO_IN_MINILZO)
+#  ifndef __LZOCONF_H
+#    include <lzoconf.h>
+#  endif
+#endif
+
+#if defined(__BOUNDS_CHECKING_ON)
+#  include <unchecked.h>
+#else
+#  define BOUNDS_CHECKING_OFF_DURING(stmt)      stmt
+#  define BOUNDS_CHECKING_OFF_IN_EXPR(expr)     (expr)
+#endif
+
+#if !defined(LZO_HAVE_CONFIG_H)
+#  include <stddef.h>
+#  include <string.h>
+#  if !defined(NO_STDLIB_H)
+#    include <stdlib.h>
+#  endif
+#  define HAVE_MEMCMP
+#  define HAVE_MEMCPY
+#  define HAVE_MEMMOVE
+#  define HAVE_MEMSET
+#else
+#  include <sys/types.h>
+#  if defined(HAVE_STDDEF_H)
+#    include <stddef.h>
+#  endif
+#  if defined(STDC_HEADERS)
+#    include <string.h>
+#    include <stdlib.h>
+#  endif
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#  define HAVE_MALLOC_H
+#  define HAVE_HALLOC
+#endif
+
+#undef NDEBUG
+#if !defined(LZO_DEBUG)
+#  define NDEBUG
+#endif
+#if defined(LZO_DEBUG) || !defined(NDEBUG)
+#  if !defined(NO_STDIO_H)
+#    include <stdio.h>
+#  endif
+#endif
+#include <assert.h>
+
+#if !defined(LZO_COMPILE_TIME_ASSERT)
+#  define LZO_COMPILE_TIME_ASSERT(expr) \
+       { typedef int __lzo_compile_time_assert_fail[1 - 2 * !(expr)]; }
+#endif
+
+#if !defined(LZO_UNUSED)
+#  if 1
+#    define LZO_UNUSED(var)     ((void)&var)
+#  elif 0
+#    define LZO_UNUSED(var)     { typedef int __lzo_unused[sizeof(var) ? 2 : 1]; }
+#  else
+#    define LZO_UNUSED(parm)    (parm = parm)
+#  endif
+#endif
+
+#if !defined(__inline__) && !defined(__GNUC__)
+#  if defined(__cplusplus)
+#    define __inline__      inline
+#  else
+#    define __inline__
+#  endif
+#endif
+
+#if defined(NO_MEMCMP)
+#  undef HAVE_MEMCMP
+#endif
+
+#if !defined(HAVE_MEMCMP)
+#  undef memcmp
+#  define memcmp    lzo_memcmp
+#endif
+#if !defined(HAVE_MEMCPY)
+#  undef memcpy
+#  define memcpy    lzo_memcpy
+#endif
+#if !defined(HAVE_MEMMOVE)
+#  undef memmove
+#  define memmove   lzo_memmove
+#endif
+#if !defined(HAVE_MEMSET)
+#  undef memset
+#  define memset    lzo_memset
+#endif
+
+#if 0
+#  define LZO_BYTE(x)       ((unsigned char) (x))
+#else
+#  define LZO_BYTE(x)       ((unsigned char) ((x) & 0xff))
+#endif
+
+#define LZO_MAX(a,b)        ((a) >= (b) ? (a) : (b))
+#define LZO_MIN(a,b)        ((a) <= (b) ? (a) : (b))
+#define LZO_MAX3(a,b,c)     ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
+#define LZO_MIN3(a,b,c)     ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))
+
+#define lzo_sizeof(type)    ((lzo_uint) (sizeof(type)))
+
+#define LZO_HIGH(array)     ((lzo_uint) (sizeof(array)/sizeof(*(array))))
+
+#define LZO_SIZE(bits)      (1u << (bits))
+#define LZO_MASK(bits)      (LZO_SIZE(bits) - 1)
+
+#define LZO_LSIZE(bits)     (1ul << (bits))
+#define LZO_LMASK(bits)     (LZO_LSIZE(bits) - 1)
+
+#define LZO_USIZE(bits)     ((lzo_uint) 1 << (bits))
+#define LZO_UMASK(bits)     (LZO_USIZE(bits) - 1)
+
+#define LZO_STYPE_MAX(b)    (((1l  << (8*(b)-2)) - 1l)  + (1l  << (8*(b)-2)))
+#define LZO_UTYPE_MAX(b)    (((1ul << (8*(b)-1)) - 1ul) + (1ul << (8*(b)-1)))
+
+#if !defined(SIZEOF_UNSIGNED)
+#  if (UINT_MAX == 0xffff)
+#    define SIZEOF_UNSIGNED         2
+#  elif (UINT_MAX == LZO_0xffffffffL)
+#    define SIZEOF_UNSIGNED         4
+#  elif (UINT_MAX >= LZO_0xffffffffL)
+#    define SIZEOF_UNSIGNED         8
+#  else
+#    error "SIZEOF_UNSIGNED"
+#  endif
+#endif
+
+#if !defined(SIZEOF_UNSIGNED_LONG)
+#  if (ULONG_MAX == LZO_0xffffffffL)
+#    define SIZEOF_UNSIGNED_LONG    4
+#  elif (ULONG_MAX >= LZO_0xffffffffL)
+#    define SIZEOF_UNSIGNED_LONG    8
+#  else
+#    error "SIZEOF_UNSIGNED_LONG"
+#  endif
+#endif
+
+#if !defined(SIZEOF_SIZE_T)
+#  define SIZEOF_SIZE_T             SIZEOF_UNSIGNED
+#endif
+#if !defined(SIZE_T_MAX)
+#  define SIZE_T_MAX                LZO_UTYPE_MAX(SIZEOF_SIZE_T)
+#endif
+
+#if 1 && defined(__LZO_i386) && (UINT_MAX == LZO_0xffffffffL)
+#  if !defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX == 0xffff)
+#    define LZO_UNALIGNED_OK_2
+#  endif
+#  if !defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX == LZO_0xffffffffL)
+#    define LZO_UNALIGNED_OK_4
+#  endif
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2) || defined(LZO_UNALIGNED_OK_4)
+#  if !defined(LZO_UNALIGNED_OK)
+#    define LZO_UNALIGNED_OK
+#  endif
+#endif
+
+#if defined(__LZO_NO_UNALIGNED)
+#  undef LZO_UNALIGNED_OK
+#  undef LZO_UNALIGNED_OK_2
+#  undef LZO_UNALIGNED_OK_4
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX != 0xffff)
+#  error "LZO_UNALIGNED_OK_2 must not be defined on this system"
+#endif
+#if defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL)
+#  error "LZO_UNALIGNED_OK_4 must not be defined on this system"
+#endif
+
+#if defined(__LZO_NO_ALIGNED)
+#  undef LZO_ALIGNED_OK_4
+#endif
+
+#if defined(LZO_ALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL)
+#  error "LZO_ALIGNED_OK_4 must not be defined on this system"
+#endif
+
+#define LZO_LITTLE_ENDIAN       1234
+#define LZO_BIG_ENDIAN          4321
+#define LZO_PDP_ENDIAN          3412
+
+#if !defined(LZO_BYTE_ORDER)
+#  if defined(MFX_BYTE_ORDER)
+#    define LZO_BYTE_ORDER      MFX_BYTE_ORDER
+#  elif defined(__LZO_i386)
+#    define LZO_BYTE_ORDER      LZO_LITTLE_ENDIAN
+#  elif defined(BYTE_ORDER)
+#    define LZO_BYTE_ORDER      BYTE_ORDER
+#  elif defined(__BYTE_ORDER)
+#    define LZO_BYTE_ORDER      __BYTE_ORDER
+#  endif
+#endif
+
+#if defined(LZO_BYTE_ORDER)
+#  if (LZO_BYTE_ORDER != LZO_LITTLE_ENDIAN) && \
+      (LZO_BYTE_ORDER != LZO_BIG_ENDIAN)
+#    error "invalid LZO_BYTE_ORDER"
+#  endif
+#endif
+
+#if defined(LZO_UNALIGNED_OK) && !defined(LZO_BYTE_ORDER)
+#  error "LZO_BYTE_ORDER is not defined"
+#endif
+
+#define LZO_OPTIMIZE_GNUC_i386_IS_BUGGY
+
+#if defined(NDEBUG) && !defined(LZO_DEBUG) && !defined(__LZO_CHECKER)
+#  if defined(__GNUC__) && defined(__i386__)
+#    if !defined(LZO_OPTIMIZE_GNUC_i386_IS_BUGGY)
+#      define LZO_OPTIMIZE_GNUC_i386
+#    endif
+#  endif
+#endif
+
+__LZO_EXTERN_C int __lzo_init_done;
+__LZO_EXTERN_C const lzo_byte __lzo_copyright[];
+LZO_EXTERN(const lzo_byte *) lzo_copyright(void);
+__LZO_EXTERN_C const lzo_uint32 _lzo_crc32_table[256];
+
+#define _LZO_STRINGIZE(x)           #x
+#define _LZO_MEXPAND(x)             _LZO_STRINGIZE(x)
+
+#define _LZO_CONCAT2(a,b)           a ## b
+#define _LZO_CONCAT3(a,b,c)         a ## b ## c
+#define _LZO_CONCAT4(a,b,c,d)       a ## b ## c ## d
+#define _LZO_CONCAT5(a,b,c,d,e)     a ## b ## c ## d ## e
+
+#define _LZO_ECONCAT2(a,b)          _LZO_CONCAT2(a,b)
+#define _LZO_ECONCAT3(a,b,c)        _LZO_CONCAT3(a,b,c)
+#define _LZO_ECONCAT4(a,b,c,d)      _LZO_CONCAT4(a,b,c,d)
+#define _LZO_ECONCAT5(a,b,c,d,e)    _LZO_CONCAT5(a,b,c,d,e)
+
+#if 0
+
+#define __LZO_IS_COMPRESS_QUERY(i,il,o,ol,w)    ((lzo_voidp)(o) == (w))
+#define __LZO_QUERY_COMPRESS(i,il,o,ol,w,n,s) \
+               (*ol = (n)*(s), LZO_E_OK)
+
+#define __LZO_IS_DECOMPRESS_QUERY(i,il,o,ol,w)  ((lzo_voidp)(o) == (w))
+#define __LZO_QUERY_DECOMPRESS(i,il,o,ol,w,n,s) \
+               (*ol = (n)*(s), LZO_E_OK)
+
+#define __LZO_IS_OPTIMIZE_QUERY(i,il,o,ol,w)    ((lzo_voidp)(o) == (w))
+#define __LZO_QUERY_OPTIMIZE(i,il,o,ol,w,n,s) \
+               (*ol = (n)*(s), LZO_E_OK)
+
+#endif
+
+#ifndef __LZO_PTR_H
+#define __LZO_PTR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#  include <dos.h>
+#  if 1 && defined(__WATCOMC__)
+#    include <i86.h>
+     __LZO_EXTERN_C unsigned char _HShift;
+#    define __LZO_HShift    _HShift
+#  elif 1 && defined(_MSC_VER)
+     __LZO_EXTERN_C unsigned short __near _AHSHIFT;
+#    define __LZO_HShift    ((unsigned) &_AHSHIFT)
+#  elif defined(__LZO_WIN16)
+#    define __LZO_HShift    3
+#  else
+#    define __LZO_HShift    12
+#  endif
+#  if !defined(_FP_SEG) && defined(FP_SEG)
+#    define _FP_SEG         FP_SEG
+#  endif
+#  if !defined(_FP_OFF) && defined(FP_OFF)
+#    define _FP_OFF         FP_OFF
+#  endif
+#endif
+
+#if !defined(lzo_ptrdiff_t)
+#  if (UINT_MAX >= LZO_0xffffffffL)
+     typedef ptrdiff_t          lzo_ptrdiff_t;
+#  else
+     typedef long               lzo_ptrdiff_t;
+#  endif
+#endif
+
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(lzo_ptr_t)
+#    define __LZO_HAVE_PTR_T
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_LONG)
+#    if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_LONG)
+       typedef unsigned long    lzo_ptr_t;
+       typedef long             lzo_sptr_t;
+#      define __LZO_HAVE_PTR_T
+#    endif
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED)
+#    if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED)
+       typedef unsigned int     lzo_ptr_t;
+       typedef int              lzo_sptr_t;
+#      define __LZO_HAVE_PTR_T
+#    endif
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_SHORT)
+#    if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_SHORT)
+       typedef unsigned short   lzo_ptr_t;
+       typedef short            lzo_sptr_t;
+#      define __LZO_HAVE_PTR_T
+#    endif
+#  endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+#  if defined(LZO_HAVE_CONFIG_H) || defined(SIZEOF_CHAR_P)
+#    error "no suitable type for lzo_ptr_t"
+#  else
+     typedef unsigned long      lzo_ptr_t;
+     typedef long               lzo_sptr_t;
+#    define __LZO_HAVE_PTR_T
+#  endif
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#define PTR(a)              ((lzo_bytep) (a))
+#define PTR_ALIGNED_4(a)    ((_FP_OFF(a) & 3) == 0)
+#define PTR_ALIGNED2_4(a,b) (((_FP_OFF(a) | _FP_OFF(b)) & 3) == 0)
+#else
+#define PTR(a)              ((lzo_ptr_t) (a))
+#define PTR_LINEAR(a)       PTR(a)
+#define PTR_ALIGNED_4(a)    ((PTR_LINEAR(a) & 3) == 0)
+#define PTR_ALIGNED_8(a)    ((PTR_LINEAR(a) & 7) == 0)
+#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
+#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
+#endif
+
+#define PTR_LT(a,b)         (PTR(a) < PTR(b))
+#define PTR_GE(a,b)         (PTR(a) >= PTR(b))
+#define PTR_DIFF(a,b)       ((lzo_ptrdiff_t) (PTR(a) - PTR(b)))
+#define pd(a,b)             ((lzo_uint) ((a)-(b)))
+
+LZO_EXTERN(lzo_ptr_t)
+__lzo_ptr_linear(const lzo_voidp ptr);
+
+typedef union
+{
+    char            a_char;
+    unsigned char   a_uchar;
+    short           a_short;
+    unsigned short  a_ushort;
+    int             a_int;
+    unsigned int    a_uint;
+    long            a_long;
+    unsigned long   a_ulong;
+    lzo_int         a_lzo_int;
+    lzo_uint        a_lzo_uint;
+    lzo_int32       a_lzo_int32;
+    lzo_uint32      a_lzo_uint32;
+    ptrdiff_t       a_ptrdiff_t;
+    lzo_ptrdiff_t   a_lzo_ptrdiff_t;
+    lzo_ptr_t       a_lzo_ptr_t;
+    lzo_voidp       a_lzo_voidp;
+    void *          a_void_p;
+    lzo_bytep       a_lzo_bytep;
+    lzo_bytepp      a_lzo_bytepp;
+    lzo_uintp       a_lzo_uintp;
+    lzo_uint *      a_lzo_uint_p;
+    lzo_uint32p     a_lzo_uint32p;
+    lzo_uint32 *    a_lzo_uint32_p;
+    unsigned char * a_uchar_p;
+    char *          a_char_p;
+}
+lzo_full_align_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#define LZO_DETERMINISTIC
+
+#define LZO_DICT_USE_PTR
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16) || defined(__LZO_STRICT_16BIT)
+#  undef LZO_DICT_USE_PTR
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+#  define lzo_dict_t    const lzo_bytep
+#  define lzo_dict_p    lzo_dict_t __LZO_MMODEL *
+#else
+#  define lzo_dict_t    lzo_uint
+#  define lzo_dict_p    lzo_dict_t __LZO_MMODEL *
+#endif
+
+#if !defined(lzo_moff_t)
+#define lzo_moff_t      lzo_uint
+#endif
+
+#endif
+
+LZO_PUBLIC(lzo_ptr_t)
+__lzo_ptr_linear(const lzo_voidp ptr)
+{
+    lzo_ptr_t p;
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+    p = (((lzo_ptr_t)(_FP_SEG(ptr))) << (16 - __LZO_HShift)) + (_FP_OFF(ptr));
+#else
+    p = PTR_LINEAR(ptr);
+#endif
+
+    return p;
+}
+
+LZO_PUBLIC(unsigned)
+__lzo_align_gap(const lzo_voidp ptr, lzo_uint size)
+{
+    lzo_ptr_t p, s, n;
+
+    assert(size > 0);
+
+    p = __lzo_ptr_linear(ptr);
+    s = (lzo_ptr_t) (size - 1);
+#if 0
+    assert((size & (size - 1)) == 0);
+    n = ((p + s) & ~s) - p;
+#else
+    n = (((p + s) / size) * size) - p;
+#endif
+
+    assert((long)n >= 0);
+    assert(n <= s);
+
+    return (unsigned)n;
+}
+
+#ifndef __LZO_UTIL_H
+#define __LZO_UTIL_H
+
+#ifndef __LZO_CONF_H
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if 1 && defined(HAVE_MEMCPY)
+#if !defined(__LZO_DOS16) && !defined(__LZO_WIN16)
+
+#define MEMCPY8_DS(dest,src,len) \
+    memcpy(dest,src,len); \
+    dest += len; \
+    src += len
+
+#endif
+#endif
+
+#if 0 && !defined(MEMCPY8_DS)
+
+#define MEMCPY8_DS(dest,src,len) \
+    { do { \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       len -= 8; \
+    } while (len > 0); }
+
+#endif
+
+#if !defined(MEMCPY8_DS)
+
+#define MEMCPY8_DS(dest,src,len) \
+    { register lzo_uint __l = (len) / 8; \
+    do { \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+       *dest++ = *src++; \
+    } while (--__l > 0); }
+
+#endif
+
+#define MEMCPY_DS(dest,src,len) \
+    do *dest++ = *src++; \
+    while (--len > 0)
+
+#define MEMMOVE_DS(dest,src,len) \
+    do *dest++ = *src++; \
+    while (--len > 0)
+
+#if 0 && defined(LZO_OPTIMIZE_GNUC_i386)
+
+#define BZERO8_PTR(s,l,n) \
+__asm__ __volatile__( \
+    "movl  %0,%%eax \n"             \
+    "movl  %1,%%edi \n"             \
+    "movl  %2,%%ecx \n"             \
+    "cld \n"                        \
+    "rep \n"                        \
+    "stosl %%eax,(%%edi) \n"        \
+    :               \
+    :"g" (0),"g" (s),"g" (n)        \
+    :"eax","edi","ecx", "memory", "cc" \
+)
+
+#elif (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMSET)
+
+#if 1
+#define BZERO8_PTR(s,l,n)   memset((s),0,(lzo_uint)(l)*(n))
+#else
+#define BZERO8_PTR(s,l,n)   memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
+#endif
+
+#else
+
+#define BZERO8_PTR(s,l,n) \
+    lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
+
+#endif
+
+#if 0
+#if defined(__GNUC__) && defined(__i386__)
+
+unsigned char lzo_rotr8(unsigned char value, int shift);
+extern __inline__ unsigned char lzo_rotr8(unsigned char value, int shift)
+{
+    unsigned char result;
+
+    __asm__ __volatile__ ("movb %b1, %b0; rorb %b2, %b0"
+                       : "=a"(result) : "g"(value), "c"(shift));
+    return result;
+}
+
+unsigned short lzo_rotr16(unsigned short value, int shift);
+extern __inline__ unsigned short lzo_rotr16(unsigned short value, int shift)
+{
+    unsigned short result;
+
+    __asm__ __volatile__ ("movw %b1, %b0; rorw %b2, %b0"
+                       : "=a"(result) : "g"(value), "c"(shift));
+    return result;
+}
+
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+LZO_PUBLIC(lzo_bool)
+lzo_assert(int expr)
+{
+    return (expr) ? 1 : 0;
+}
+
+/* If you use the LZO library in a product, you *must* keep this
+ * copyright string in the executable of your product.
+ */
+
+const lzo_byte __lzo_copyright[] =
+#if !defined(__LZO_IN_MINLZO)
+    LZO_VERSION_STRING;
+#else
+    "\n\n\n"
+    "LZO real-time data compression library.\n"
+    "Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Markus Franz Xaver Johannes Oberhumer\n"
+    "<markus.oberhumer@jk.uni-linz.ac.at>\n"
+    "http://www.oberhumer.com/opensource/lzo/\n"
+    "\n"
+    "LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE "\n"
+    "LZO build date: " __DATE__ " " __TIME__ "\n\n"
+    "LZO special compilation options:\n"
+#ifdef __cplusplus
+    " __cplusplus\n"
+#endif
+#if defined(__PIC__)
+    " __PIC__\n"
+#elif defined(__pic__)
+    " __pic__\n"
+#endif
+#if (UINT_MAX < LZO_0xffffffffL)
+    " 16BIT\n"
+#endif
+#if defined(__LZO_STRICT_16BIT)
+    " __LZO_STRICT_16BIT\n"
+#endif
+#if (UINT_MAX > LZO_0xffffffffL)
+    " UINT_MAX=" _LZO_MEXPAND(UINT_MAX) "\n"
+#endif
+#if (ULONG_MAX > LZO_0xffffffffL)
+    " ULONG_MAX=" _LZO_MEXPAND(ULONG_MAX) "\n"
+#endif
+#if defined(LZO_BYTE_ORDER)
+    " LZO_BYTE_ORDER=" _LZO_MEXPAND(LZO_BYTE_ORDER) "\n"
+#endif
+#if defined(LZO_UNALIGNED_OK_2)
+    " LZO_UNALIGNED_OK_2\n"
+#endif
+#if defined(LZO_UNALIGNED_OK_4)
+    " LZO_UNALIGNED_OK_4\n"
+#endif
+#if defined(LZO_ALIGNED_OK_4)
+    " LZO_ALIGNED_OK_4\n"
+#endif
+#if defined(LZO_DICT_USE_PTR)
+    " LZO_DICT_USE_PTR\n"
+#endif
+#if defined(__LZO_QUERY_COMPRESS)
+    " __LZO_QUERY_COMPRESS\n"
+#endif
+#if defined(__LZO_QUERY_DECOMPRESS)
+    " __LZO_QUERY_DECOMPRESS\n"
+#endif
+#if defined(__LZO_IN_MINILZO)
+    " __LZO_IN_MINILZO\n"
+#endif
+    "\n\n"
+    "$Id: LZO " LZO_VERSION_STRING " built " __DATE__ " " __TIME__
+#if defined(__GNUC__) && defined(__VERSION__)
+    " by gcc " __VERSION__
+#elif defined(__BORLANDC__)
+    " by Borland C " _LZO_MEXPAND(__BORLANDC__)
+#elif defined(_MSC_VER)
+    " by Microsoft C " _LZO_MEXPAND(_MSC_VER)
+#elif defined(__PUREC__)
+    " by Pure C " _LZO_MEXPAND(__PUREC__)
+#elif defined(__SC__)
+    " by Symantec C " _LZO_MEXPAND(__SC__)
+#elif defined(__TURBOC__)
+    " by Turbo C " _LZO_MEXPAND(__TURBOC__)
+#elif defined(__WATCOMC__)
+    " by Watcom C " _LZO_MEXPAND(__WATCOMC__)
+#endif
+    " $\n"
+    "$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Markus Franz Xaver Johannes Oberhumer $\n";
+#endif
+
+LZO_PUBLIC(const lzo_byte *)
+lzo_copyright(void)
+{
+    return __lzo_copyright;
+}
+
+LZO_PUBLIC(unsigned)
+lzo_version(void)
+{
+    return LZO_VERSION;
+}
+
+LZO_PUBLIC(const char *)
+lzo_version_string(void)
+{
+    return LZO_VERSION_STRING;
+}
+
+LZO_PUBLIC(const char *)
+lzo_version_date(void)
+{
+    return LZO_VERSION_DATE;
+}
+
+LZO_PUBLIC(const lzo_charp)
+_lzo_version_string(void)
+{
+    return LZO_VERSION_STRING;
+}
+
+LZO_PUBLIC(const lzo_charp)
+_lzo_version_date(void)
+{
+    return LZO_VERSION_DATE;
+}
+
+#define LZO_BASE 65521u
+#define LZO_NMAX 5552
+
+#define LZO_DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define LZO_DO2(buf,i)  LZO_DO1(buf,i); LZO_DO1(buf,i+1);
+#define LZO_DO4(buf,i)  LZO_DO2(buf,i); LZO_DO2(buf,i+2);
+#define LZO_DO8(buf,i)  LZO_DO4(buf,i); LZO_DO4(buf,i+4);
+#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
+
+LZO_PUBLIC(lzo_uint32)
+lzo_adler32(lzo_uint32 adler, const lzo_byte *buf, lzo_uint len)
+{
+    lzo_uint32 s1 = adler & 0xffff;
+    lzo_uint32 s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == NULL)
+       return 1;
+
+    while (len > 0)
+    {
+       k = len < LZO_NMAX ? (int) len : LZO_NMAX;
+       len -= k;
+       if (k >= 16) do
+       {
+           LZO_DO16(buf,0);
+           buf += 16;
+           k -= 16;
+       } while (k >= 16);
+       if (k != 0) do
+       {
+           s1 += *buf++;
+           s2 += s1;
+       } while (--k > 0);
+       s1 %= LZO_BASE;
+       s2 %= LZO_BASE;
+    }
+    return (s2 << 16) | s1;
+}
+
+LZO_PUBLIC(int)
+lzo_memcmp(const lzo_voidp s1, const lzo_voidp s2, lzo_uint len)
+{
+#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMCMP)
+    return memcmp(s1,s2,len);
+#else
+    const lzo_byte *p1 = (const lzo_byte *) s1;
+    const lzo_byte *p2 = (const lzo_byte *) s2;
+    int d;
+
+    if (len > 0) do
+    {
+       d = *p1 - *p2;
+       if (d != 0)
+           return d;
+       p1++;
+       p2++;
+    }
+    while (--len > 0);
+    return 0;
+#endif
+}
+
+LZO_PUBLIC(lzo_voidp)
+lzo_memcpy(lzo_voidp dest, const lzo_voidp src, lzo_uint len)
+{
+#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMCPY)
+    return memcpy(dest,src,len);
+#else
+    lzo_byte *p1 = (lzo_byte *) dest;
+    const lzo_byte *p2 = (const lzo_byte *) src;
+
+    if (len <= 0 || p1 == p2)
+       return dest;
+    do
+       *p1++ = *p2++;
+    while (--len > 0);
+    return dest;
+#endif
+}
+
+LZO_PUBLIC(lzo_voidp)
+lzo_memmove(lzo_voidp dest, const lzo_voidp src, lzo_uint len)
+{
+#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMMOVE)
+    return memmove(dest,src,len);
+#else
+    lzo_byte *p1 = (lzo_byte *) dest;
+    const lzo_byte *p2 = (const lzo_byte *) src;
+
+    if (len <= 0 || p1 == p2)
+       return dest;
+
+    if (p1 < p2)
+    {
+       do
+           *p1++ = *p2++;
+       while (--len > 0);
+    }
+    else
+    {
+       p1 += len;
+       p2 += len;
+       do
+           *--p1 = *--p2;
+       while (--len > 0);
+    }
+    return dest;
+#endif
+}
+
+LZO_PUBLIC(lzo_voidp)
+lzo_memset(lzo_voidp s, int c, lzo_uint len)
+{
+#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMSET)
+    return memset(s,c,len);
+#else
+    lzo_byte *p = (lzo_byte *) s;
+
+    if (len > 0) do
+       *p++ = LZO_BYTE(c);
+    while (--len > 0);
+    return s;
+#endif
+}
+
+#if 0
+#  define IS_SIGNED(type)       (((type) (1ul << (8 * sizeof(type) - 1))) < 0)
+#  define IS_UNSIGNED(type)     (((type) (1ul << (8 * sizeof(type) - 1))) > 0)
+#else
+#  define IS_SIGNED(type)       (((type) (-1)) < ((type) 0))
+#  define IS_UNSIGNED(type)     (((type) (-1)) > ((type) 0))
+#endif
+
+#define IS_POWER_OF_2(x)        (((x) & ((x) - 1)) == 0)
+
+static lzo_bool schedule_insns_bug(void);
+static lzo_bool strength_reduce_bug(int *);
+
+#if 0 || defined(LZO_DEBUG)
+#include <stdio.h>
+static lzo_bool __lzo_assert_fail(const char *s, unsigned line)
+{
+#if defined(__palmos__)
+    printf("LZO assertion failed in line %u: '%s'\n",line,s);
+#else
+    fprintf(stderr,"LZO assertion failed in line %u: '%s'\n",line,s);
+#endif
+    return 0;
+}
+#  define __lzo_assert(x)   ((x) ? 1 : __lzo_assert_fail(#x,__LINE__))
+#else
+#  define __lzo_assert(x)   ((x) ? 1 : 0)
+#endif
+
+#undef COMPILE_TIME_ASSERT
+#if 0
+#  define COMPILE_TIME_ASSERT(expr)     r &= __lzo_assert(expr)
+#else
+#  define COMPILE_TIME_ASSERT(expr)     LZO_COMPILE_TIME_ASSERT(expr)
+#endif
+
+static lzo_bool basic_integral_check(void)
+{
+    lzo_bool r = 1;
+
+    COMPILE_TIME_ASSERT(CHAR_BIT == 8);
+    COMPILE_TIME_ASSERT(sizeof(char) == 1);
+    COMPILE_TIME_ASSERT(sizeof(short) >= 2);
+    COMPILE_TIME_ASSERT(sizeof(long) >= 4);
+    COMPILE_TIME_ASSERT(sizeof(int) >= sizeof(short));
+    COMPILE_TIME_ASSERT(sizeof(long) >= sizeof(int));
+
+    COMPILE_TIME_ASSERT(sizeof(lzo_uint) == sizeof(lzo_int));
+    COMPILE_TIME_ASSERT(sizeof(lzo_uint32) == sizeof(lzo_int32));
+
+    COMPILE_TIME_ASSERT(sizeof(lzo_uint32) >= 4);
+    COMPILE_TIME_ASSERT(sizeof(lzo_uint32) >= sizeof(unsigned));
+#if defined(__LZO_STRICT_16BIT)
+    COMPILE_TIME_ASSERT(sizeof(lzo_uint) == 2);
+#else
+    COMPILE_TIME_ASSERT(sizeof(lzo_uint) >= 4);
+    COMPILE_TIME_ASSERT(sizeof(lzo_uint) >= sizeof(unsigned));
+#endif
+
+#if (USHRT_MAX == 65535u)
+    COMPILE_TIME_ASSERT(sizeof(short) == 2);
+#elif (USHRT_MAX == LZO_0xffffffffL)
+    COMPILE_TIME_ASSERT(sizeof(short) == 4);
+#elif (USHRT_MAX >= LZO_0xffffffffL)
+    COMPILE_TIME_ASSERT(sizeof(short) > 4);
+#endif
+#if (UINT_MAX == 65535u)
+    COMPILE_TIME_ASSERT(sizeof(int) == 2);
+#elif (UINT_MAX == LZO_0xffffffffL)
+    COMPILE_TIME_ASSERT(sizeof(int) == 4);
+#elif (UINT_MAX >= LZO_0xffffffffL)
+    COMPILE_TIME_ASSERT(sizeof(int) > 4);
+#endif
+#if (ULONG_MAX == 65535ul)
+    COMPILE_TIME_ASSERT(sizeof(long) == 2);
+#elif (ULONG_MAX == LZO_0xffffffffL)
+    COMPILE_TIME_ASSERT(sizeof(long) == 4);
+#elif (ULONG_MAX >= LZO_0xffffffffL)
+    COMPILE_TIME_ASSERT(sizeof(long) > 4);
+#endif
+
+#if defined(SIZEOF_UNSIGNED)
+    COMPILE_TIME_ASSERT(SIZEOF_UNSIGNED == sizeof(unsigned));
+#endif
+#if defined(SIZEOF_UNSIGNED_LONG)
+    COMPILE_TIME_ASSERT(SIZEOF_UNSIGNED_LONG == sizeof(unsigned long));
+#endif
+#if defined(SIZEOF_UNSIGNED_SHORT)
+    COMPILE_TIME_ASSERT(SIZEOF_UNSIGNED_SHORT == sizeof(unsigned short));
+#endif
+#if !defined(__LZO_IN_MINILZO)
+#if defined(SIZEOF_SIZE_T)
+    COMPILE_TIME_ASSERT(SIZEOF_SIZE_T == sizeof(size_t));
+#endif
+#endif
+
+    COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned char));
+    COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned short));
+    COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned));
+    COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned long));
+    COMPILE_TIME_ASSERT(IS_SIGNED(short));
+    COMPILE_TIME_ASSERT(IS_SIGNED(int));
+    COMPILE_TIME_ASSERT(IS_SIGNED(long));
+
+    COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_uint32));
+    COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_uint));
+    COMPILE_TIME_ASSERT(IS_SIGNED(lzo_int32));
+    COMPILE_TIME_ASSERT(IS_SIGNED(lzo_int));
+
+    COMPILE_TIME_ASSERT(INT_MAX    == LZO_STYPE_MAX(sizeof(int)));
+    COMPILE_TIME_ASSERT(UINT_MAX   == LZO_UTYPE_MAX(sizeof(unsigned)));
+    COMPILE_TIME_ASSERT(LONG_MAX   == LZO_STYPE_MAX(sizeof(long)));
+    COMPILE_TIME_ASSERT(ULONG_MAX  == LZO_UTYPE_MAX(sizeof(unsigned long)));
+    COMPILE_TIME_ASSERT(SHRT_MAX   == LZO_STYPE_MAX(sizeof(short)));
+    COMPILE_TIME_ASSERT(USHRT_MAX  == LZO_UTYPE_MAX(sizeof(unsigned short)));
+    COMPILE_TIME_ASSERT(LZO_UINT32_MAX == LZO_UTYPE_MAX(sizeof(lzo_uint32)));
+    COMPILE_TIME_ASSERT(LZO_UINT_MAX   == LZO_UTYPE_MAX(sizeof(lzo_uint)));
+#if !defined(__LZO_IN_MINILZO)
+    COMPILE_TIME_ASSERT(SIZE_T_MAX     == LZO_UTYPE_MAX(sizeof(size_t)));
+#endif
+
+    r &= __lzo_assert(LZO_BYTE(257) == 1);
+
+    return r;
+}
+
+static lzo_bool basic_ptr_check(void)
+{
+    lzo_bool r = 1;
+
+    COMPILE_TIME_ASSERT(sizeof(char *) >= sizeof(int));
+    COMPILE_TIME_ASSERT(sizeof(lzo_byte *) >= sizeof(char *));
+
+    COMPILE_TIME_ASSERT(sizeof(lzo_voidp) == sizeof(lzo_byte *));
+    COMPILE_TIME_ASSERT(sizeof(lzo_voidp) == sizeof(lzo_voidpp));
+    COMPILE_TIME_ASSERT(sizeof(lzo_voidp) == sizeof(lzo_bytepp));
+    COMPILE_TIME_ASSERT(sizeof(lzo_voidp) >= sizeof(lzo_uint));
+
+    COMPILE_TIME_ASSERT(sizeof(lzo_ptr_t) == sizeof(lzo_voidp));
+    COMPILE_TIME_ASSERT(sizeof(lzo_ptr_t) == sizeof(lzo_sptr_t));
+    COMPILE_TIME_ASSERT(sizeof(lzo_ptr_t) >= sizeof(lzo_uint));
+
+    COMPILE_TIME_ASSERT(sizeof(lzo_ptrdiff_t) >= 4);
+    COMPILE_TIME_ASSERT(sizeof(lzo_ptrdiff_t) >= sizeof(ptrdiff_t));
+
+    COMPILE_TIME_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t));
+    COMPILE_TIME_ASSERT(sizeof(lzo_ptrdiff_t) >= sizeof(lzo_uint));
+
+#if defined(SIZEOF_CHAR_P)
+    COMPILE_TIME_ASSERT(SIZEOF_CHAR_P == sizeof(char *));
+#endif
+#if defined(SIZEOF_PTRDIFF_T)
+    COMPILE_TIME_ASSERT(SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t));
+#endif
+
+    COMPILE_TIME_ASSERT(IS_SIGNED(ptrdiff_t));
+    COMPILE_TIME_ASSERT(IS_UNSIGNED(size_t));
+    COMPILE_TIME_ASSERT(IS_SIGNED(lzo_ptrdiff_t));
+    COMPILE_TIME_ASSERT(IS_SIGNED(lzo_sptr_t));
+    COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_ptr_t));
+    COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_moff_t));
+
+    return r;
+}
+
+static lzo_bool ptr_check(void)
+{
+    lzo_bool r = 1;
+    int i;
+    char _wrkmem[10 * sizeof(lzo_byte *) + sizeof(lzo_full_align_t)];
+    lzo_bytep wrkmem;
+    lzo_bytepp dict;
+    unsigned char x[4 * sizeof(lzo_full_align_t)];
+    long d;
+    lzo_full_align_t a;
+    lzo_full_align_t u;
+
+    for (i = 0; i < (int) sizeof(x); i++)
+       x[i] = LZO_BYTE(i);
+
+    wrkmem = LZO_PTR_ALIGN_UP((lzo_byte *)_wrkmem,sizeof(lzo_full_align_t));
+
+#if 0
+    dict = (lzo_bytepp) wrkmem;
+#else
+
+    u.a_lzo_bytep = wrkmem; dict = u.a_lzo_bytepp;
+#endif
+
+    d = (long) ((const lzo_bytep) dict - (const lzo_bytep) _wrkmem);
+    r &= __lzo_assert(d >= 0);
+    r &= __lzo_assert(d < (long) sizeof(lzo_full_align_t));
+
+    memset(&a,0,sizeof(a));
+    r &= __lzo_assert(a.a_lzo_voidp == NULL);
+
+    memset(&a,0xff,sizeof(a));
+    r &= __lzo_assert(a.a_ushort == USHRT_MAX);
+    r &= __lzo_assert(a.a_uint == UINT_MAX);
+    r &= __lzo_assert(a.a_ulong == ULONG_MAX);
+    r &= __lzo_assert(a.a_lzo_uint == LZO_UINT_MAX);
+    r &= __lzo_assert(a.a_lzo_uint32 == LZO_UINT32_MAX);
+
+    if (r == 1)
+    {
+       for (i = 0; i < 8; i++)
+           r &= __lzo_assert((const lzo_voidp) (&dict[i]) == (const lzo_voidp) (&wrkmem[i * sizeof(lzo_byte *)]));
+    }
+
+    memset(&a,0,sizeof(a));
+    r &= __lzo_assert(a.a_char_p == NULL);
+    r &= __lzo_assert(a.a_lzo_bytep == NULL);
+    r &= __lzo_assert(NULL == (void *)0);
+    if (r == 1)
+    {
+       for (i = 0; i < 10; i++)
+           dict[i] = wrkmem;
+       BZERO8_PTR(dict+1,sizeof(dict[0]),8);
+       r &= __lzo_assert(dict[0] == wrkmem);
+       for (i = 1; i < 9; i++)
+           r &= __lzo_assert(dict[i] == NULL);
+       r &= __lzo_assert(dict[9] == wrkmem);
+    }
+
+    if (r == 1)
+    {
+       unsigned k = 1;
+       const unsigned n = (unsigned) sizeof(lzo_uint32);
+       lzo_byte *p0;
+       lzo_byte *p1;
+
+       k += __lzo_align_gap(&x[k],n);
+       p0 = (lzo_bytep) &x[k];
+#if defined(PTR_LINEAR)
+       r &= __lzo_assert((PTR_LINEAR(p0) & (n-1)) == 0);
+#else
+       r &= __lzo_assert(n == 4);
+       r &= __lzo_assert(PTR_ALIGNED_4(p0));
+#endif
+
+       r &= __lzo_assert(k >= 1);
+       p1 = (lzo_bytep) &x[1];
+       r &= __lzo_assert(PTR_GE(p0,p1));
+
+       r &= __lzo_assert(k < 1+n);
+       p1 = (lzo_bytep) &x[1+n];
+       r &= __lzo_assert(PTR_LT(p0,p1));
+
+       if (r == 1)
+       {
+           lzo_uint32 v0, v1;
+#if 0
+           v0 = * (lzo_uint32 *) &x[k];
+           v1 = * (lzo_uint32 *) &x[k+n];
+#else
+
+           u.a_uchar_p = &x[k];
+           v0 = *u.a_lzo_uint32_p;
+           u.a_uchar_p = &x[k+n];
+           v1 = *u.a_lzo_uint32_p;
+#endif
+           r &= __lzo_assert(v0 > 0);
+           r &= __lzo_assert(v1 > 0);
+       }
+    }
+
+    return r;
+}
+
+LZO_PUBLIC(int)
+_lzo_config_check(void)
+{
+    lzo_bool r = 1;
+    int i;
+    union {
+       lzo_uint32 a;
+       unsigned short b;
+       lzo_uint32 aa[4];
+       unsigned char x[4*sizeof(lzo_full_align_t)];
+    } u;
+
+    COMPILE_TIME_ASSERT( (int) ((unsigned char) ((signed char) -1)) == 255);
+    COMPILE_TIME_ASSERT( (((unsigned char)128) << (int)(8*sizeof(int)-8)) < 0);
+
+#if 0
+    r &= __lzo_assert((const void *)&u == (const void *)&u.a);
+    r &= __lzo_assert((const void *)&u == (const void *)&u.b);
+    r &= __lzo_assert((const void *)&u == (const void *)&u.x[0]);
+    r &= __lzo_assert((const void *)&u == (const void *)&u.aa[0]);
+#endif
+
+    r &= basic_integral_check();
+    r &= basic_ptr_check();
+    if (r != 1)
+       return LZO_E_ERROR;
+
+    u.a = 0; u.b = 0;
+    for (i = 0; i < (int) sizeof(u.x); i++)
+       u.x[i] = LZO_BYTE(i);
+
+#if defined(LZO_BYTE_ORDER)
+    if (r == 1)
+    {
+#  if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+       lzo_uint32 a = (lzo_uint32) (u.a & LZO_0xffffffffL);
+       unsigned short b = (unsigned short) (u.b & 0xffff);
+       r &= __lzo_assert(a == 0x03020100L);
+       r &= __lzo_assert(b == 0x0100);
+#  elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN)
+       lzo_uint32 a = u.a >> (8 * sizeof(u.a) - 32);
+       unsigned short b = u.b >> (8 * sizeof(u.b) - 16);
+       r &= __lzo_assert(a == 0x00010203L);
+       r &= __lzo_assert(b == 0x0001);
+#  else
+#    error "invalid LZO_BYTE_ORDER"
+#  endif
+    }
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2)
+    COMPILE_TIME_ASSERT(sizeof(short) == 2);
+    if (r == 1)
+    {
+       unsigned short b[4];
+
+       for (i = 0; i < 4; i++)
+           b[i] = * (const unsigned short *) &u.x[i];
+
+#  if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+       r &= __lzo_assert(b[0] == 0x0100);
+       r &= __lzo_assert(b[1] == 0x0201);
+       r &= __lzo_assert(b[2] == 0x0302);
+       r &= __lzo_assert(b[3] == 0x0403);
+#  elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN)
+       r &= __lzo_assert(b[0] == 0x0001);
+       r &= __lzo_assert(b[1] == 0x0102);
+       r &= __lzo_assert(b[2] == 0x0203);
+       r &= __lzo_assert(b[3] == 0x0304);
+#  endif
+    }
+#endif
+
+#if defined(LZO_UNALIGNED_OK_4)
+    COMPILE_TIME_ASSERT(sizeof(lzo_uint32) == 4);
+    if (r == 1)
+    {
+       lzo_uint32 a[4];
+
+       for (i = 0; i < 4; i++)
+           a[i] = * (const lzo_uint32 *) &u.x[i];
+
+#  if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+       r &= __lzo_assert(a[0] == 0x03020100L);
+       r &= __lzo_assert(a[1] == 0x04030201L);
+       r &= __lzo_assert(a[2] == 0x05040302L);
+       r &= __lzo_assert(a[3] == 0x06050403L);
+#  elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN)
+       r &= __lzo_assert(a[0] == 0x00010203L);
+       r &= __lzo_assert(a[1] == 0x01020304L);
+       r &= __lzo_assert(a[2] == 0x02030405L);
+       r &= __lzo_assert(a[3] == 0x03040506L);
+#  endif
+    }
+#endif
+
+#if defined(LZO_ALIGNED_OK_4)
+    COMPILE_TIME_ASSERT(sizeof(lzo_uint32) == 4);
+#endif
+
+    COMPILE_TIME_ASSERT(lzo_sizeof_dict_t == sizeof(lzo_dict_t));
+
+#if defined(__LZO_IN_MINLZO)
+    if (r == 1)
+    {
+       lzo_uint32 adler;
+       adler = lzo_adler32(0, NULL, 0);
+       adler = lzo_adler32(adler, lzo_copyright(), 200);
+       r &= __lzo_assert(adler == 0xc76f1751L);
+    }
+#endif
+
+    if (r == 1)
+    {
+       r &= __lzo_assert(!schedule_insns_bug());
+    }
+
+    if (r == 1)
+    {
+       static int x[3];
+       static unsigned xn = 3;
+       register unsigned j;
+
+       for (j = 0; j < xn; j++)
+           x[j] = (int)j - 3;
+       r &= __lzo_assert(!strength_reduce_bug(x));
+    }
+
+    if (r == 1)
+    {
+       r &= ptr_check();
+    }
+
+    return r == 1 ? LZO_E_OK : LZO_E_ERROR;
+}
+
+static lzo_bool schedule_insns_bug(void)
+{
+#if defined(__LZO_CHECKER)
+    return 0;
+#else
+    const int clone[] = {1, 2, 0};
+    const int *q;
+    q = clone;
+    return (*q) ? 0 : 1;
+#endif
+}
+
+static lzo_bool strength_reduce_bug(int *x)
+{
+    return x[0] != -3 || x[1] != -2 || x[2] != -1;
+}
+
+#undef COMPILE_TIME_ASSERT
+
+int __lzo_init_done = 0;
+
+LZO_PUBLIC(int)
+__lzo_init2(unsigned v, int s1, int s2, int s3, int s4, int s5,
+                       int s6, int s7, int s8, int s9)
+{
+    int r;
+
+    __lzo_init_done = 1;
+
+    if (v == 0)
+       return LZO_E_ERROR;
+
+    r = (s1 == -1 || s1 == (int) sizeof(short)) &&
+       (s2 == -1 || s2 == (int) sizeof(int)) &&
+       (s3 == -1 || s3 == (int) sizeof(long)) &&
+       (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) &&
+       (s5 == -1 || s5 == (int) sizeof(lzo_uint)) &&
+       (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) &&
+       (s7 == -1 || s7 == (int) sizeof(char *)) &&
+       (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) &&
+       (s9 == -1 || s9 == (int) sizeof(lzo_compress_t));
+    if (!r)
+       return LZO_E_ERROR;
+
+    r = _lzo_config_check();
+    if (r != LZO_E_OK)
+       return r;
+
+    return r;
+}
+
+#if !defined(__LZO_IN_MINILZO)
+
+LZO_EXTERN(int)
+__lzo_init(unsigned v,int s1,int s2,int s3,int s4,int s5,int s6,int s7);
+
+LZO_PUBLIC(int)
+__lzo_init(unsigned v,int s1,int s2,int s3,int s4,int s5,int s6,int s7)
+{
+    if (v == 0 || v > 0x1010)
+       return LZO_E_ERROR;
+    return __lzo_init2(v,s1,s2,s3,s4,s5,-1,-1,s6,s7);
+}
+
+#endif
+
+#define do_compress         _lzo1x_1_do_compress
+
+#define LZO_NEED_DICT_H
+#define D_BITS          14
+#define D_INDEX1(d,p)       d = DM((0x21*DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p)       d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#ifndef __LZO_CONFIG1X_H
+#define __LZO_CONFIG1X_H
+
+#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z)
+#  define LZO1X
+#endif
+
+#if !defined(__LZO_IN_MINILZO)
+#include <lzo1x.h>
+#endif
+
+#define LZO_EOF_CODE
+#undef LZO_DETERMINISTIC
+
+#define M1_MAX_OFFSET   0x0400
+#ifndef M2_MAX_OFFSET
+#define M2_MAX_OFFSET   0x0800
+#endif
+#define M3_MAX_OFFSET   0x4000
+#define M4_MAX_OFFSET   0xbfff
+
+#define MX_MAX_OFFSET   (M1_MAX_OFFSET + M2_MAX_OFFSET)
+
+#define M1_MIN_LEN      2
+#define M1_MAX_LEN      2
+#define M2_MIN_LEN      3
+#ifndef M2_MAX_LEN
+#define M2_MAX_LEN      8
+#endif
+#define M3_MIN_LEN      3
+#define M3_MAX_LEN      33
+#define M4_MIN_LEN      3
+#define M4_MAX_LEN      9
+
+#define M1_MARKER       0
+#define M2_MARKER       64
+#define M3_MARKER       32
+#define M4_MARKER       16
+
+#ifndef MIN_LOOKAHEAD
+#define MIN_LOOKAHEAD       (M2_MAX_LEN + 1)
+#endif
+
+#if defined(LZO_NEED_DICT_H)
+
+#ifndef LZO_HASH
+#define LZO_HASH            LZO_HASH_LZO_INCREMENTAL_B
+#endif
+#define DL_MIN_LEN          M2_MIN_LEN
+
+#ifndef __LZO_DICT_H
+#define __LZO_DICT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(D_BITS) && defined(DBITS)
+#  define D_BITS        DBITS
+#endif
+#if !defined(D_BITS)
+#  error "D_BITS is not defined"
+#endif
+#if (D_BITS < 16)
+#  define D_SIZE        LZO_SIZE(D_BITS)
+#  define D_MASK        LZO_MASK(D_BITS)
+#else
+#  define D_SIZE        LZO_USIZE(D_BITS)
+#  define D_MASK        LZO_UMASK(D_BITS)
+#endif
+#define D_HIGH          ((D_MASK >> 1) + 1)
+
+#if !defined(DD_BITS)
+#  define DD_BITS       0
+#endif
+#define DD_SIZE         LZO_SIZE(DD_BITS)
+#define DD_MASK         LZO_MASK(DD_BITS)
+
+#if !defined(DL_BITS)
+#  define DL_BITS       (D_BITS - DD_BITS)
+#endif
+#if (DL_BITS < 16)
+#  define DL_SIZE       LZO_SIZE(DL_BITS)
+#  define DL_MASK       LZO_MASK(DL_BITS)
+#else
+#  define DL_SIZE       LZO_USIZE(DL_BITS)
+#  define DL_MASK       LZO_UMASK(DL_BITS)
+#endif
+
+#if (D_BITS != DL_BITS + DD_BITS)
+#  error "D_BITS does not match"
+#endif
+#if (D_BITS < 8 || D_BITS > 18)
+#  error "invalid D_BITS"
+#endif
+#if (DL_BITS < 8 || DL_BITS > 20)
+#  error "invalid DL_BITS"
+#endif
+#if (DD_BITS < 0 || DD_BITS > 6)
+#  error "invalid DD_BITS"
+#endif
+
+#if !defined(DL_MIN_LEN)
+#  define DL_MIN_LEN    3
+#endif
+#if !defined(DL_SHIFT)
+#  define DL_SHIFT      ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN)
+#endif
+
+#define LZO_HASH_GZIP                   1
+#define LZO_HASH_GZIP_INCREMENTAL       2
+#define LZO_HASH_LZO_INCREMENTAL_A      3
+#define LZO_HASH_LZO_INCREMENTAL_B      4
+
+#if !defined(LZO_HASH)
+#  error "choose a hashing strategy"
+#endif
+
+#if (DL_MIN_LEN == 3)
+#  define _DV2_A(p,shift1,shift2) \
+       (((( (lzo_uint32)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2])
+#  define _DV2_B(p,shift1,shift2) \
+       (((( (lzo_uint32)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0])
+#  define _DV3_B(p,shift1,shift2,shift3) \
+       ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0])
+#elif (DL_MIN_LEN == 2)
+#  define _DV2_A(p,shift1,shift2) \
+       (( (lzo_uint32)(p[0]) << shift1) ^ p[1])
+#  define _DV2_B(p,shift1,shift2) \
+       (( (lzo_uint32)(p[1]) << shift1) ^ p[2])
+#else
+#  error "invalid DL_MIN_LEN"
+#endif
+#define _DV_A(p,shift)      _DV2_A(p,shift,shift)
+#define _DV_B(p,shift)      _DV2_B(p,shift,shift)
+#define DA2(p,s1,s2) \
+       (((((lzo_uint32)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0])
+#define DS2(p,s1,s2) \
+       (((((lzo_uint32)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0])
+#define DX2(p,s1,s2) \
+       (((((lzo_uint32)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
+#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
+#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
+#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
+#define DMS(v,s)        ((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))
+#define DM(v)           DMS(v,0)
+
+#if (LZO_HASH == LZO_HASH_GZIP)
+#  define _DINDEX(dv,p)     (_DV_A((p),DL_SHIFT))
+
+#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL)
+#  define __LZO_HASH_INCREMENTAL
+#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),DL_SHIFT)
+#  define DVAL_NEXT(dv,p)   dv = (((dv) << DL_SHIFT) ^ p[2])
+#  define _DINDEX(dv,p)     (dv)
+#  define DVAL_LOOKAHEAD    DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A)
+#  define __LZO_HASH_INCREMENTAL
+#  define DVAL_FIRST(dv,p)  dv = _DV_A((p),5)
+#  define DVAL_NEXT(dv,p) \
+               dv ^= (lzo_uint32)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2])
+#  define _DINDEX(dv,p)     ((0x9f5f * (dv)) >> 5)
+#  define DVAL_LOOKAHEAD    DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B)
+#  define __LZO_HASH_INCREMENTAL
+#  define DVAL_FIRST(dv,p)  dv = _DV_B((p),5)
+#  define DVAL_NEXT(dv,p) \
+               dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_uint32)(p[2]) << (2*5)))
+#  define _DINDEX(dv,p)     ((0x9f5f * (dv)) >> 5)
+#  define DVAL_LOOKAHEAD    DL_MIN_LEN
+
+#else
+#  error "choose a hashing strategy"
+#endif
+
+#ifndef DINDEX
+#define DINDEX(dv,p)        ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS)
+#endif
+#if !defined(DINDEX1) && defined(D_INDEX1)
+#define DINDEX1             D_INDEX1
+#endif
+#if !defined(DINDEX2) && defined(D_INDEX2)
+#define DINDEX2             D_INDEX2
+#endif
+
+#if !defined(__LZO_HASH_INCREMENTAL)
+#  define DVAL_FIRST(dv,p)  ((void) 0)
+#  define DVAL_NEXT(dv,p)   ((void) 0)
+#  define DVAL_LOOKAHEAD    0
+#endif
+
+#if !defined(DVAL_ASSERT)
+#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)
+static void DVAL_ASSERT(lzo_uint32 dv, const lzo_byte *p)
+{
+    lzo_uint32 df;
+    DVAL_FIRST(df,(p));
+    assert(DINDEX(dv,p) == DINDEX(df,p));
+}
+#else
+#  define DVAL_ASSERT(dv,p) ((void) 0)
+#endif
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+#  define DENTRY(p,in)                          (p)
+#  define GINDEX(m_pos,m_off,dict,dindex,in)    m_pos = dict[dindex]
+#else
+#  define DENTRY(p,in)                          ((lzo_uint) ((p)-(in)))
+#  define GINDEX(m_pos,m_off,dict,dindex,in)    m_off = dict[dindex]
+#endif
+
+#if (DD_BITS == 0)
+
+#  define UPDATE_D(dict,drun,dv,p,in)       dict[ DINDEX(dv,p) ] = DENTRY(p,in)
+#  define UPDATE_I(dict,drun,index,p,in)    dict[index] = DENTRY(p,in)
+#  define UPDATE_P(ptr,drun,p,in)           (ptr)[0] = DENTRY(p,in)
+
+#else
+
+#  define UPDATE_D(dict,drun,dv,p,in)   \
+       dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+#  define UPDATE_I(dict,drun,index,p,in)    \
+       dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+#  define UPDATE_P(ptr,drun,p,in)   \
+       (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK
+
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+       (m_pos == NULL || (m_off = (lzo_moff_t) (ip - m_pos)) > max_offset)
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+    (BOUNDS_CHECKING_OFF_IN_EXPR( \
+       (PTR_LT(m_pos,in) || \
+        (m_off = (lzo_moff_t) PTR_DIFF(ip,m_pos)) <= 0 || \
+         m_off > max_offset) ))
+
+#else
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+       (m_off == 0 || \
+        ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \
+        (m_pos = (ip) - (m_off), 0) )
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+       ((lzo_moff_t) ((ip)-(in)) <= m_off || \
+        ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \
+        (m_pos = (ip) - (m_off), 0) )
+
+#endif
+
+#if defined(LZO_DETERMINISTIC)
+#  define LZO_CHECK_MPOS    LZO_CHECK_MPOS_DET
+#else
+#  define LZO_CHECK_MPOS    LZO_CHECK_MPOS_NON_DET
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
+
+#endif
+
+#define DO_COMPRESS     lzo1x_1_compress
+
+static
+lzo_uint do_compress     ( const lzo_byte *in , lzo_uint  in_len,
+                                lzo_byte *out, lzo_uintp out_len,
+                                lzo_voidp wrkmem )
+{
+#if 0 && defined(__GNUC__) && defined(__i386__)
+    register const lzo_byte *ip __asm__("%esi");
+#else
+    register const lzo_byte *ip;
+#endif
+    lzo_byte *op;
+    const lzo_byte * const in_end = in + in_len;
+    const lzo_byte * const ip_end = in + in_len - M2_MAX_LEN - 5;
+    const lzo_byte *ii;
+    lzo_dict_p const dict = (lzo_dict_p) wrkmem;
+
+    op = out;
+    ip = in;
+    ii = ip;
+
+    ip += 4;
+    for (;;)
+    {
+#if 0 && defined(__GNUC__) && defined(__i386__)
+       register const lzo_byte *m_pos __asm__("%edi");
+#else
+       register const lzo_byte *m_pos;
+#endif
+       lzo_moff_t m_off;
+       lzo_uint m_len;
+       lzo_uint dindex;
+
+       DINDEX1(dindex,ip);
+       GINDEX(m_pos,m_off,dict,dindex,in);
+       if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+           goto literal;
+#if 1
+       if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+           goto try_match;
+       DINDEX2(dindex,ip);
+#endif
+       GINDEX(m_pos,m_off,dict,dindex,in);
+       if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+           goto literal;
+       if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+           goto try_match;
+       goto literal;
+
+try_match:
+#if 1 && defined(LZO_UNALIGNED_OK_2)
+       if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
+#else
+       if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
+#endif
+       {
+       }
+       else
+       {
+           if (m_pos[2] == ip[2])
+           {
+#if 0
+               if (m_off <= M2_MAX_OFFSET)
+                   goto match;
+               if (lit <= 3)
+                   goto match;
+               if (lit == 3)
+               {
+                   assert(op - 2 > out); op[-2] |= LZO_BYTE(3);
+                   *op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
+                   goto code_match;
+               }
+               if (m_pos[3] == ip[3])
+#endif
+                   goto match;
+           }
+           else
+           {
+#if 0
+#if 0
+               if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3)
+#else
+               if (m_off <= M1_MAX_OFFSET && lit == 3)
+#endif
+               {
+                   register lzo_uint t;
+
+                   t = lit;
+                   assert(op - 2 > out); op[-2] |= LZO_BYTE(t);
+                   do *op++ = *ii++; while (--t > 0);
+                   assert(ii == ip);
+                   m_off -= 1;
+                   *op++ = LZO_BYTE(M1_MARKER | ((m_off & 3) << 2));
+                   *op++ = LZO_BYTE(m_off >> 2);
+                   ip += 2;
+                   goto match_done;
+               }
+#endif
+           }
+       }
+
+literal:
+       UPDATE_I(dict,0,dindex,ip,in);
+       ++ip;
+       if (ip >= ip_end)
+           break;
+       continue;
+
+match:
+       UPDATE_I(dict,0,dindex,ip,in);
+       if (pd(ip,ii) > 0)
+       {
+           register lzo_uint t = pd(ip,ii);
+
+           if (t <= 3)
+           {
+               assert(op - 2 > out);
+               op[-2] |= LZO_BYTE(t);
+           }
+           else if (t <= 18)
+               *op++ = LZO_BYTE(t - 3);
+           else
+           {
+               register lzo_uint tt = t - 18;
+
+               *op++ = 0;
+               while (tt > 255)
+               {
+                   tt -= 255;
+                   *op++ = 0;
+               }
+               assert(tt > 0);
+               *op++ = LZO_BYTE(tt);
+           }
+           do *op++ = *ii++; while (--t > 0);
+       }
+
+       assert(ii == ip);
+       ip += 3;
+       if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ ||
+           m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++
+#ifdef LZO1Y
+           || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++
+           || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++
+#endif
+          )
+       {
+           --ip;
+           m_len = ip - ii;
+           assert(m_len >= 3); assert(m_len <= M2_MAX_LEN);
+
+           if (m_off <= M2_MAX_OFFSET)
+           {
+               m_off -= 1;
+#if defined(LZO1X)
+               *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
+               *op++ = LZO_BYTE(m_off >> 3);
+#elif defined(LZO1Y)
+               *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2));
+               *op++ = LZO_BYTE(m_off >> 2);
+#endif
+           }
+           else if (m_off <= M3_MAX_OFFSET)
+           {
+               m_off -= 1;
+               *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
+               goto m3_m4_offset;
+           }
+           else
+#if defined(LZO1X)
+           {
+               m_off -= 0x4000;
+               assert(m_off > 0); assert(m_off <= 0x7fff);
+               *op++ = LZO_BYTE(M4_MARKER |
+                                ((m_off & 0x4000) >> 11) | (m_len - 2));
+               goto m3_m4_offset;
+           }
+#elif defined(LZO1Y)
+               goto m4_match;
+#endif
+       }
+       else
+       {
+           {
+               const lzo_byte *end = in_end;
+               const lzo_byte *m = m_pos + M2_MAX_LEN + 1;
+               while (ip < end && *m == *ip)
+                   m++, ip++;
+               m_len = (ip - ii);
+           }
+           assert(m_len > M2_MAX_LEN);
+
+           if (m_off <= M3_MAX_OFFSET)
+           {
+               m_off -= 1;
+               if (m_len <= 33)
+                   *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
+               else
+               {
+                   m_len -= 33;
+                   *op++ = M3_MARKER | 0;
+                   goto m3_m4_len;
+               }
+           }
+           else
+           {
+#if defined(LZO1Y)
+m4_match:
+#endif
+               m_off -= 0x4000;
+               assert(m_off > 0); assert(m_off <= 0x7fff);
+               if (m_len <= M4_MAX_LEN)
+                   *op++ = LZO_BYTE(M4_MARKER |
+                                    ((m_off & 0x4000) >> 11) | (m_len - 2));
+               else
+               {
+                   m_len -= M4_MAX_LEN;
+                   *op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11));
+m3_m4_len:
+                   while (m_len > 255)
+                   {
+                       m_len -= 255;
+                       *op++ = 0;
+                   }
+                   assert(m_len > 0);
+                   *op++ = LZO_BYTE(m_len);
+               }
+           }
+
+m3_m4_offset:
+           *op++ = LZO_BYTE((m_off & 63) << 2);
+           *op++ = LZO_BYTE(m_off >> 6);
+       }
+
+#if 0
+match_done:
+#endif
+       ii = ip;
+       if (ip >= ip_end)
+           break;
+    }
+
+    *out_len = op - out;
+    return pd(in_end,ii);
+}
+
+LZO_PUBLIC(int)
+DO_COMPRESS      ( const lzo_byte *in , lzo_uint  in_len,
+                        lzo_byte *out, lzo_uintp out_len,
+                        lzo_voidp wrkmem )
+{
+    lzo_byte *op = out;
+    lzo_uint t;
+
+#if defined(__LZO_QUERY_COMPRESS)
+    if (__LZO_IS_COMPRESS_QUERY(in,in_len,out,out_len,wrkmem))
+       return __LZO_QUERY_COMPRESS(in,in_len,out,out_len,wrkmem,D_SIZE,lzo_sizeof(lzo_dict_t));
+#endif
+
+    if (in_len <= M2_MAX_LEN + 5)
+       t = in_len;
+    else
+    {
+       t = do_compress(in,in_len,op,out_len,wrkmem);
+       op += *out_len;
+    }
+
+    if (t > 0)
+    {
+       const lzo_byte *ii = in + in_len - t;
+
+       if (op == out && t <= 238)
+           *op++ = LZO_BYTE(17 + t);
+       else if (t <= 3)
+           op[-2] |= LZO_BYTE(t);
+       else if (t <= 18)
+           *op++ = LZO_BYTE(t - 3);
+       else
+       {
+           lzo_uint tt = t - 18;
+
+           *op++ = 0;
+           while (tt > 255)
+           {
+               tt -= 255;
+               *op++ = 0;
+           }
+           assert(tt > 0);
+           *op++ = LZO_BYTE(tt);
+       }
+       do *op++ = *ii++; while (--t > 0);
+    }
+
+    *op++ = M4_MARKER | 1;
+    *op++ = 0;
+    *op++ = 0;
+
+    *out_len = op - out;
+    return LZO_E_OK;
+}
+
+#undef do_compress
+#undef DO_COMPRESS
+#undef LZO_HASH
+
+#undef LZO_TEST_DECOMPRESS_OVERRUN
+#undef LZO_TEST_DECOMPRESS_OVERRUN_INPUT
+#undef LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT
+#undef LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS       lzo1x_decompress
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN)
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_INPUT       2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT      2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+#  endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LOOKBEHIND
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1)
+#    define TEST_IP             (ip < ip_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2)
+#    define NEED_IP(x) \
+           if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1)
+#    define TEST_OP             (op <= op_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2)
+#    undef TEST_OP
+#    define NEED_OP(x) \
+           if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#  define TEST_LOOKBEHIND(m_pos,out)    if (m_pos < out) goto lookbehind_overrun
+#else
+#  define TEST_LOOKBEHIND(m_pos,op)     ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+#  define TEST_IP               (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+#  define HAVE_TEST_IP
+#else
+#  define TEST_IP               1
+#endif
+#if defined(TEST_OP)
+#  define HAVE_TEST_OP
+#else
+#  define TEST_OP               1
+#endif
+
+#if defined(NEED_IP)
+#  define HAVE_NEED_IP
+#else
+#  define NEED_IP(x)            ((void) 0)
+#endif
+#if defined(NEED_OP)
+#  define HAVE_NEED_OP
+#else
+#  define NEED_OP(x)            ((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+#  define HAVE_ANY_IP
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+#  define HAVE_ANY_OP
+#endif
+
+#undef __COPY4
+#define __COPY4(dst,src)    * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
+
+#undef COPY4
+#if defined(LZO_UNALIGNED_OK_4)
+#  define COPY4(dst,src)    __COPY4(dst,src)
+#elif defined(LZO_ALIGNED_OK_4)
+#  define COPY4(dst,src)    __COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+DO_DECOMPRESS  ( const lzo_byte *in , lzo_uint  in_len,
+                      lzo_byte *out, lzo_uintp out_len,
+                      lzo_voidp wrkmem )
+#endif
+{
+    register lzo_byte *op;
+    register const lzo_byte *ip;
+    register lzo_uint t;
+#if defined(COPY_DICT)
+    lzo_uint m_off;
+    const lzo_byte *dict_end;
+#else
+    register const lzo_byte *m_pos;
+#endif
+
+    const lzo_byte * const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+    lzo_byte * const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+    lzo_uint last_m_off = 0;
+#endif
+
+    LZO_UNUSED(wrkmem);
+
+#if defined(__LZO_QUERY_DECOMPRESS)
+    if (__LZO_IS_DECOMPRESS_QUERY(in,in_len,out,out_len,wrkmem))
+       return __LZO_QUERY_DECOMPRESS(in,in_len,out,out_len,wrkmem,0,0);
+#endif
+
+#if defined(COPY_DICT)
+    if (dict)
+    {
+       if (dict_len > M4_MAX_OFFSET)
+       {
+           dict += dict_len - M4_MAX_OFFSET;
+           dict_len = M4_MAX_OFFSET;
+       }
+       dict_end = dict + dict_len;
+    }
+    else
+    {
+       dict_len = 0;
+       dict_end = NULL;
+    }
+#endif
+
+    *out_len = 0;
+
+    op = out;
+    ip = in;
+
+    if (*ip > 17)
+    {
+       t = *ip++ - 17;
+       if (t < 4)
+           goto match_next;
+       assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+       do *op++ = *ip++; while (--t > 0);
+       goto first_literal_run;
+    }
+
+    while (TEST_IP && TEST_OP)
+    {
+       t = *ip++;
+       if (t >= 16)
+           goto match;
+       if (t == 0)
+       {
+           NEED_IP(1);
+           while (*ip == 0)
+           {
+               t += 255;
+               ip++;
+               NEED_IP(1);
+           }
+           t += 15 + *ip++;
+       }
+       assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+       if (PTR_ALIGNED2_4(op,ip))
+       {
+#endif
+       COPY4(op,ip);
+       op += 4; ip += 4;
+       if (--t > 0)
+       {
+           if (t >= 4)
+           {
+               do {
+                   COPY4(op,ip);
+                   op += 4; ip += 4; t -= 4;
+               } while (t >= 4);
+               if (t > 0) do *op++ = *ip++; while (--t > 0);
+           }
+           else
+               do *op++ = *ip++; while (--t > 0);
+       }
+#if !defined(LZO_UNALIGNED_OK_4)
+       }
+       else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+       {
+           *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+           do *op++ = *ip++; while (--t > 0);
+       }
+#endif
+
+first_literal_run:
+
+       t = *ip++;
+       if (t >= 16)
+           goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+       m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+       last_m_off = m_off;
+#else
+       m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+       NEED_OP(3);
+       t = 3; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+       t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+       m_pos = op - t;
+       last_m_off = t;
+#else
+       m_pos = op - (1 + M2_MAX_OFFSET);
+       m_pos -= t >> 2;
+       m_pos -= *ip++ << 2;
+#endif
+       TEST_LOOKBEHIND(m_pos,out); NEED_OP(3);
+       *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+       goto match_done;
+
+       while (TEST_IP && TEST_OP)
+       {
+match:
+           if (t >= 64)
+           {
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+               m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+               t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+               m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+               t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+               m_off = t & 0x1f;
+               if (m_off >= 0x1c)
+                   m_off = last_m_off;
+               else
+               {
+                   m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+                   last_m_off = m_off;
+               }
+               t = (t >> 5) - 1;
+#endif
+#else
+#if defined(LZO1X)
+               m_pos = op - 1;
+               m_pos -= (t >> 2) & 7;
+               m_pos -= *ip++ << 3;
+               t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+               m_pos = op - 1;
+               m_pos -= (t >> 2) & 3;
+               m_pos -= *ip++ << 2;
+               t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+               {
+                   lzo_uint off = t & 0x1f;
+                   m_pos = op;
+                   if (off >= 0x1c)
+                   {
+                       assert(last_m_off > 0);
+                       m_pos -= last_m_off;
+                   }
+                   else
+                   {
+                       off = 1 + (off << 6) + (*ip++ >> 2);
+                       m_pos -= off;
+                       last_m_off = off;
+                   }
+               }
+               t = (t >> 5) - 1;
+#endif
+               TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
+               goto copy_match;
+#endif
+           }
+           else if (t >= 32)
+           {
+               t &= 31;
+               if (t == 0)
+               {
+                   NEED_IP(1);
+                   while (*ip == 0)
+                   {
+                       t += 255;
+                       ip++;
+                       NEED_IP(1);
+                   }
+                   t += 31 + *ip++;
+               }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+               m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+               last_m_off = m_off;
+#else
+               m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else
+#if defined(LZO1Z)
+               {
+                   lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+                   m_pos = op - off;
+                   last_m_off = off;
+               }
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+               m_pos = op - 1;
+               m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+               m_pos = op - 1;
+               m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif
+               ip += 2;
+           }
+           else if (t >= 16)
+           {
+#if defined(COPY_DICT)
+               m_off = (t & 8) << 11;
+#else
+               m_pos = op;
+               m_pos -= (t & 8) << 11;
+#endif
+               t &= 7;
+               if (t == 0)
+               {
+                   NEED_IP(1);
+                   while (*ip == 0)
+                   {
+                       t += 255;
+                       ip++;
+                       NEED_IP(1);
+                   }
+                   t += 7 + *ip++;
+               }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+               m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+               m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+               ip += 2;
+               if (m_off == 0)
+                   goto eof_found;
+               m_off += 0x4000;
+#if defined(LZO1Z)
+               last_m_off = m_off;
+#endif
+#else
+#if defined(LZO1Z)
+               m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+               m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+               m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+               ip += 2;
+               if (m_pos == op)
+                   goto eof_found;
+               m_pos -= 0x4000;
+#if defined(LZO1Z)
+               last_m_off = op - m_pos;
+#endif
+#endif
+           }
+           else
+           {
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+               m_off = 1 + (t << 6) + (*ip++ >> 2);
+               last_m_off = m_off;
+#else
+               m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+               NEED_OP(2);
+               t = 2; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+               t = 1 + (t << 6) + (*ip++ >> 2);
+               m_pos = op - t;
+               last_m_off = t;
+#else
+               m_pos = op - 1;
+               m_pos -= t >> 2;
+               m_pos -= *ip++ << 2;
+#endif
+               TEST_LOOKBEHIND(m_pos,out); NEED_OP(2);
+               *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+               goto match_done;
+           }
+
+#if defined(COPY_DICT)
+
+           NEED_OP(t+3-1);
+           t += 3-1; COPY_DICT(t,m_off)
+
+#else
+
+           TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+           if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+           {
+               assert((op - m_pos) >= 4);
+#else
+           if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+           {
+#endif
+               COPY4(op,m_pos);
+               op += 4; m_pos += 4; t -= 4 - (3 - 1);
+               do {
+                   COPY4(op,m_pos);
+                   op += 4; m_pos += 4; t -= 4;
+               } while (t >= 4);
+               if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+           }
+           else
+#endif
+           {
+copy_match:
+               *op++ = *m_pos++; *op++ = *m_pos++;
+               do *op++ = *m_pos++; while (--t > 0);
+           }
+
+#endif
+
+match_done:
+#if defined(LZO1Z)
+           t = ip[-1] & 3;
+#else
+           t = ip[-2] & 3;
+#endif
+           if (t == 0)
+               break;
+
+match_next:
+           assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+           do *op++ = *ip++; while (--t > 0);
+           t = *ip++;
+       }
+    }
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+    *out_len = op - out;
+    return LZO_E_EOF_NOT_FOUND;
+#endif
+
+eof_found:
+    assert(t == 1);
+    *out_len = op - out;
+    return (ip == ip_end ? LZO_E_OK :
+          (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+input_overrun:
+    *out_len = op - out;
+    return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+output_overrun:
+    *out_len = op - out;
+    return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+lookbehind_overrun:
+    *out_len = op - out;
+    return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+#define LZO_TEST_DECOMPRESS_OVERRUN
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS       lzo1x_decompress_safe
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN)
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_INPUT       2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT      2
+#  endif
+#  if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#    define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+#  endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LOOKBEHIND
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1)
+#    define TEST_IP             (ip < ip_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2)
+#    define NEED_IP(x) \
+           if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1)
+#    define TEST_OP             (op <= op_end)
+#  endif
+#  if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2)
+#    undef TEST_OP
+#    define NEED_OP(x) \
+           if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
+#  endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+#  define TEST_LOOKBEHIND(m_pos,out)    if (m_pos < out) goto lookbehind_overrun
+#else
+#  define TEST_LOOKBEHIND(m_pos,op)     ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+#  define TEST_IP               (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+#  define HAVE_TEST_IP
+#else
+#  define TEST_IP               1
+#endif
+#if defined(TEST_OP)
+#  define HAVE_TEST_OP
+#else
+#  define TEST_OP               1
+#endif
+
+#if defined(NEED_IP)
+#  define HAVE_NEED_IP
+#else
+#  define NEED_IP(x)            ((void) 0)
+#endif
+#if defined(NEED_OP)
+#  define HAVE_NEED_OP
+#else
+#  define NEED_OP(x)            ((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+#  define HAVE_ANY_IP
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+#  define HAVE_ANY_OP
+#endif
+
+#undef __COPY4
+#define __COPY4(dst,src)    * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
+
+#undef COPY4
+#if defined(LZO_UNALIGNED_OK_4)
+#  define COPY4(dst,src)    __COPY4(dst,src)
+#elif defined(LZO_ALIGNED_OK_4)
+#  define COPY4(dst,src)    __COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+DO_DECOMPRESS  ( const lzo_byte *in , lzo_uint  in_len,
+                      lzo_byte *out, lzo_uintp out_len,
+                      lzo_voidp wrkmem )
+#endif
+{
+    register lzo_byte *op;
+    register const lzo_byte *ip;
+    register lzo_uint t;
+#if defined(COPY_DICT)
+    lzo_uint m_off;
+    const lzo_byte *dict_end;
+#else
+    register const lzo_byte *m_pos;
+#endif
+
+    const lzo_byte * const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+    lzo_byte * const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+    lzo_uint last_m_off = 0;
+#endif
+
+    LZO_UNUSED(wrkmem);
+
+#if defined(__LZO_QUERY_DECOMPRESS)
+    if (__LZO_IS_DECOMPRESS_QUERY(in,in_len,out,out_len,wrkmem))
+       return __LZO_QUERY_DECOMPRESS(in,in_len,out,out_len,wrkmem,0,0);
+#endif
+
+#if defined(COPY_DICT)
+    if (dict)
+    {
+       if (dict_len > M4_MAX_OFFSET)
+       {
+           dict += dict_len - M4_MAX_OFFSET;
+           dict_len = M4_MAX_OFFSET;
+       }
+       dict_end = dict + dict_len;
+    }
+    else
+    {
+       dict_len = 0;
+       dict_end = NULL;
+    }
+#endif
+
+    *out_len = 0;
+
+    op = out;
+    ip = in;
+
+    if (*ip > 17)
+    {
+       t = *ip++ - 17;
+       if (t < 4)
+           goto match_next;
+       assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+       do *op++ = *ip++; while (--t > 0);
+       goto first_literal_run;
+    }
+
+    while (TEST_IP && TEST_OP)
+    {
+       t = *ip++;
+       if (t >= 16)
+           goto match;
+       if (t == 0)
+       {
+           NEED_IP(1);
+           while (*ip == 0)
+           {
+               t += 255;
+               ip++;
+               NEED_IP(1);
+           }
+           t += 15 + *ip++;
+       }
+       assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+       if (PTR_ALIGNED2_4(op,ip))
+       {
+#endif
+       COPY4(op,ip);
+       op += 4; ip += 4;
+       if (--t > 0)
+       {
+           if (t >= 4)
+           {
+               do {
+                   COPY4(op,ip);
+                   op += 4; ip += 4; t -= 4;
+               } while (t >= 4);
+               if (t > 0) do *op++ = *ip++; while (--t > 0);
+           }
+           else
+               do *op++ = *ip++; while (--t > 0);
+       }
+#if !defined(LZO_UNALIGNED_OK_4)
+       }
+       else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+       {
+           *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+           do *op++ = *ip++; while (--t > 0);
+       }
+#endif
+
+first_literal_run:
+
+       t = *ip++;
+       if (t >= 16)
+           goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+       m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+       last_m_off = m_off;
+#else
+       m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+       NEED_OP(3);
+       t = 3; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+       t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+       m_pos = op - t;
+       last_m_off = t;
+#else
+       m_pos = op - (1 + M2_MAX_OFFSET);
+       m_pos -= t >> 2;
+       m_pos -= *ip++ << 2;
+#endif
+       TEST_LOOKBEHIND(m_pos,out); NEED_OP(3);
+       *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+       goto match_done;
+
+       while (TEST_IP && TEST_OP)
+       {
+match:
+           if (t >= 64)
+           {
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+               m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+               t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+               m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+               t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+               m_off = t & 0x1f;
+               if (m_off >= 0x1c)
+                   m_off = last_m_off;
+               else
+               {
+                   m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+                   last_m_off = m_off;
+               }
+               t = (t >> 5) - 1;
+#endif
+#else
+#if defined(LZO1X)
+               m_pos = op - 1;
+               m_pos -= (t >> 2) & 7;
+               m_pos -= *ip++ << 3;
+               t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+               m_pos = op - 1;
+               m_pos -= (t >> 2) & 3;
+               m_pos -= *ip++ << 2;
+               t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+               {
+                   lzo_uint off = t & 0x1f;
+                   m_pos = op;
+                   if (off >= 0x1c)
+                   {
+                       assert(last_m_off > 0);
+                       m_pos -= last_m_off;
+                   }
+                   else
+                   {
+                       off = 1 + (off << 6) + (*ip++ >> 2);
+                       m_pos -= off;
+                       last_m_off = off;
+                   }
+               }
+               t = (t >> 5) - 1;
+#endif
+               TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
+               goto copy_match;
+#endif
+           }
+           else if (t >= 32)
+           {
+               t &= 31;
+               if (t == 0)
+               {
+                   NEED_IP(1);
+                   while (*ip == 0)
+                   {
+                       t += 255;
+                       ip++;
+                       NEED_IP(1);
+                   }
+                   t += 31 + *ip++;
+               }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+               m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+               last_m_off = m_off;
+#else
+               m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else
+#if defined(LZO1Z)
+               {
+                   lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+                   m_pos = op - off;
+                   last_m_off = off;
+               }
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+               m_pos = op - 1;
+               m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+               m_pos = op - 1;
+               m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif
+               ip += 2;
+           }
+           else if (t >= 16)
+           {
+#if defined(COPY_DICT)
+               m_off = (t & 8) << 11;
+#else
+               m_pos = op;
+               m_pos -= (t & 8) << 11;
+#endif
+               t &= 7;
+               if (t == 0)
+               {
+                   NEED_IP(1);
+                   while (*ip == 0)
+                   {
+                       t += 255;
+                       ip++;
+                       NEED_IP(1);
+                   }
+                   t += 7 + *ip++;
+               }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+               m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+               m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+               ip += 2;
+               if (m_off == 0)
+                   goto eof_found;
+               m_off += 0x4000;
+#if defined(LZO1Z)
+               last_m_off = m_off;
+#endif
+#else
+#if defined(LZO1Z)
+               m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+               m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+               m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+               ip += 2;
+               if (m_pos == op)
+                   goto eof_found;
+               m_pos -= 0x4000;
+#if defined(LZO1Z)
+               last_m_off = op - m_pos;
+#endif
+#endif
+           }
+           else
+           {
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+               m_off = 1 + (t << 6) + (*ip++ >> 2);
+               last_m_off = m_off;
+#else
+               m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+               NEED_OP(2);
+               t = 2; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+               t = 1 + (t << 6) + (*ip++ >> 2);
+               m_pos = op - t;
+               last_m_off = t;
+#else
+               m_pos = op - 1;
+               m_pos -= t >> 2;
+               m_pos -= *ip++ << 2;
+#endif
+               TEST_LOOKBEHIND(m_pos,out); NEED_OP(2);
+               *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+               goto match_done;
+           }
+
+#if defined(COPY_DICT)
+
+           NEED_OP(t+3-1);
+           t += 3-1; COPY_DICT(t,m_off)
+
+#else
+
+           TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+           if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+           {
+               assert((op - m_pos) >= 4);
+#else
+           if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+           {
+#endif
+               COPY4(op,m_pos);
+               op += 4; m_pos += 4; t -= 4 - (3 - 1);
+               do {
+                   COPY4(op,m_pos);
+                   op += 4; m_pos += 4; t -= 4;
+               } while (t >= 4);
+               if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+           }
+           else
+#endif
+           {
+copy_match:
+               *op++ = *m_pos++; *op++ = *m_pos++;
+               do *op++ = *m_pos++; while (--t > 0);
+           }
+
+#endif
+
+match_done:
+#if defined(LZO1Z)
+           t = ip[-1] & 3;
+#else
+           t = ip[-2] & 3;
+#endif
+           if (t == 0)
+               break;
+
+match_next:
+           assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+           do *op++ = *ip++; while (--t > 0);
+           t = *ip++;
+       }
+    }
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+    *out_len = op - out;
+    return LZO_E_EOF_NOT_FOUND;
+#endif
+
+eof_found:
+    assert(t == 1);
+    *out_len = op - out;
+    return (ip == ip_end ? LZO_E_OK :
+          (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+input_overrun:
+    *out_len = op - out;
+    return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+output_overrun:
+    *out_len = op - out;
+    return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+lookbehind_overrun:
+    *out_len = op - out;
+    return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+/***** End of minilzo.c *****/
+
diff --git a/compat/lib/rmtflags.c b/compat/lib/rmtflags.c
new file mode 100644 (file)
index 0000000..5181f1c
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: rmtflags.c,v 1.3 2003/03/30 15:40:35 stelian Exp $";
+#endif /* not linux */
+
+/*
+ * rmt
+ */
+#include <config.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <rmtflags.h>
+
+struct openflags {
+       char    *name;
+       int     value;
+} openflags[] = {
+       { "O_RDONLY",   O_RDONLY },
+       { "O_WRONLY",   O_WRONLY },
+       { "O_RDWR",     O_RDWR },
+#ifdef O_CREAT
+       { "O_CREAT",    O_CREAT },
+#endif
+#ifdef O_EXCL
+       { "O_EXCL",     O_EXCL },
+#endif
+#ifdef O_NOCTTY
+       { "O_NOCTTY",   O_NOCTTY },
+#endif
+#ifdef O_TRUNC
+       { "O_TRUNC",    O_TRUNC },
+#endif
+#ifdef O_APPEND
+       { "O_APPEND",   O_APPEND },
+#endif
+#ifdef O_NONBLOCK
+       { "O_NONBLOCK", O_NONBLOCK },
+#endif
+#ifdef O_NDELAY
+       { "O_NDELAY",   O_NDELAY },
+#endif
+#ifdef O_SYNC
+       { "O_SYNC",     O_SYNC },
+#endif
+#ifdef O_FSYNC
+       { "O_FSYNC",    O_FSYNC },
+#endif
+#ifdef O_ASYNC
+       { "O_ASYNC",    O_ASYNC },
+#endif
+#ifdef O_TEXT
+       { "O_TEXT",     O_TEXT },
+#endif
+#ifdef O_DSYNC
+       { "O_DSYNC",    O_DSYNC },
+#endif
+#ifdef O_RSYNC
+       { "O_RSYNC",    O_RSYNC },
+#endif
+#ifdef O_PRIV
+       { "O_PRIV",     O_PRIV },
+#endif
+#ifdef O_LARGEFILE
+       { "O_LARGEFILE",O_LARGEFILE },
+#endif
+       { NULL,         0 }
+};
+
+/* Parts of this stolen again from Jörg Schilling's star package... */
+int
+rmtflags_toint(char *filemode)
+{
+       char    *p = filemode;
+       struct openflags *op;
+       int     result = 0;
+       int     numresult = 0;
+       int     seentext = 0;
+
+       do {
+               /* skip space */
+               while (*p != '\0' && *p == ' ')
+                       p++;
+               /* get O_XXXX constant */
+               if (p[0] != 'O' || p[1] != '_') {
+                       /* numeric syntax detected */
+                       numresult = atoi(filemode);
+                       numresult &= O_RDONLY | O_WRONLY | O_RDWR;
+                       while (*p != ' ' && *p != '\0')
+                               p++;
+                       while (*p != '\0' && *p == ' ')
+                               p++;
+               }
+
+               if (*p == '\0')
+                       break;
+
+               /* translate O_XXXX constant */
+               for (op = openflags; op->name; op++) {
+                       int slen = strlen(op->name);
+                       if ((strncmp(op->name, p, slen) == 0) &&
+                           (p[slen] == '|' || p[slen] == ' ' ||
+                            p[slen] == '\0')) {
+                               seentext = 1;
+                               result |= op->value;
+                               break;
+                       }
+               }
+
+               /* goto next constant */
+               p = strchr(p, '|');
+       } while (p && *p++ == '|');
+
+       if (!seentext)
+               result = numresult;
+       return result;
+}
+
+char *
+rmtflags_tochar(int filemode)
+{
+       struct openflags *op;
+       char *result = (char *) malloc(4096);   /* enough space */
+
+       switch (filemode & O_ACCMODE) {
+       case O_RDONLY: 
+               strcpy(result, "O_RDONLY"); 
+               break;
+       case O_WRONLY: 
+               strcpy(result, "O_WRONLY");
+               break;
+       case O_RDWR: 
+               strcpy(result, "O_RDWR");
+               break;
+       default:
+               strcat(result, "ERROR");
+       }
+       for (op = openflags; op->name; op++) {
+               if (op->value == O_RDONLY ||
+                   op->value == O_WRONLY ||
+                   op->value == O_RDWR)
+                       continue;
+               if (filemode & op->value) {
+                       strcat(result, "|");
+                       strcat(result, op->name);
+               }
+       }
+       return result;
+}
diff --git a/compat/lib/system.c b/compat/lib/system.c
new file mode 100644 (file)
index 0000000..b3b7932
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1980, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: system.c,v 1.4 2003/03/30 15:40:35 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "system.h"
+
+/*
+ * Executes the command in a shell.
+ * Returns -1 if an error occured, the exit status of
+ * the command on success.
+ */
+int system_command(const char *command, const char *device, int volnum) {
+       int pid, status;
+       char commandstr[4096];
+
+       pid = fork();
+       if (pid == -1) {
+               perror("  DUMP: unable to fork");
+               return -1;
+       }
+       if (pid == 0) {
+               setuid(getuid());
+               setgid(getgid());
+#if OLD_STYLE_FSCRIPT
+               snprintf(commandstr, sizeof(commandstr), "%s", command);
+#else
+               snprintf(commandstr, sizeof(commandstr), "%s %s %d", command, device, volnum);
+#endif
+               commandstr[sizeof(commandstr) - 1] = '\0';
+               execl("/bin/sh", "sh", "-c", commandstr, NULL);
+               perror("unable to execute shell");
+               exit(-1);
+       }
+       do {
+               if (waitpid(pid, &status, 0) == -1) {
+                       if (errno != EINTR) {
+                               perror("waitpid error");
+                               return -1;
+                       }
+               } else {
+                       if (WIFEXITED(status))
+                               return WEXITSTATUS(status);
+                       else
+                               return -1;
+               }
+       } while(1);
+}
+
diff --git a/config.guess b/config.guess
new file mode 100755 (executable)
index 0000000..fd30ab0
--- /dev/null
@@ -0,0 +1,1354 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002 Free Software Foundation, Inc.
+
+timestamp='2002-07-23'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# This shell variable is my proudest work .. or something. --bje
+
+set_cc_for_build='tmpdir=${TMPDIR-/tmp}/config-guess-$$ ;
+(old=`umask` && umask 077 && mkdir $tmpdir && umask $old && unset old)
+   || (echo "$me: cannot create $tmpdir" >&2 && exit 1) ;
+dummy=$tmpdir/dummy ;
+files="$dummy.c $dummy.o $dummy.rel $dummy" ;
+trap '"'"'rm -f $files; rmdir $tmpdir; exit 1'"'"' 1 2 15 ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
+       rm -f $files ;
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found ;
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ;
+unset files'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # NetBSD (nbsd) targets should (where applicable) match one or
+       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE_ARCH}" in
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep __ELF__ >/dev/null
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # The OS release
+       release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit 0 ;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    macppc:OpenBSD:*:*)
+       echo powerpc-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvmeppc:OpenBSD:*:*)
+       echo powerpc-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    pmax:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mipseb-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sun3:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    alpha:OSF1:*:*)
+       if test $UNAME_RELEASE = "V4.0"; then
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+       fi
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       eval $set_cc_for_build
+       cat <<EOF >$dummy.s
+       .data
+\$Lformat:
+       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
+
+       .text
+       .globl main
+       .align 4
+       .ent main
+main:
+       .frame \$30,16,\$26,0
+       ldgp \$29,0(\$27)
+       .prologue 1
+       .long 0x47e03d80 # implver \$0
+       lda \$2,-1
+       .long 0x47e20c21 # amask \$2,\$1
+       lda \$16,\$Lformat
+       mov \$0,\$17
+       not \$1,\$18
+       jsr \$26,printf
+       ldgp \$29,0(\$26)
+       mov 0,\$16
+       jsr \$26,exit
+       .end main
+EOF
+       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               case `$dummy` in
+                       0-0)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       1-0)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       1-1)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       1-101)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       2-303)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       2-307)
+                               UNAME_MACHINE="alphaev67"
+                               ;;
+                       2-1307)
+                               UNAME_MACHINE="alphaev68"
+                               ;;
+                       3-1307)
+                               UNAME_MACHINE="alphaev7"
+                               ;;
+               esac
+       fi
+       rm -f $dummy.s $dummy && rmdir $tmpdir
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit 0;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit 0 ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
+       exit 0 ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    DRS?6000:UNIX_SV:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7 && exit 0 ;;
+       esac ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy \
+         && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0
+       rm -f $dummy.c $dummy && rmdir $tmpdir
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit 0 ;;
+    Night_Hawk:*:*:PowerMAX_OS)
+       echo powerpc-harris-powermax
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               eval $set_cc_for_build
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               $CC_FOR_BUILD $dummy.c -o $dummy && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0
+               rm -f $dummy.c $dummy && rmdir $tmpdir
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:[45])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+               if [ -x /usr/bin/getconf ]; then
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+                   (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`$dummy`
+                   if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+                   rm -f $dummy.c $dummy && rmdir $tmpdir
+               fi ;;
+       esac
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD $dummy.c -o $dummy && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0
+       rm -f $dummy.c $dummy && rmdir $tmpdir
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+             -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3D:*:*:*)
+       echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*)
+       # Determine whether the default compiler uses glibc.
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <features.h>
+       #if __GLIBC__ >= 2
+       LIBC=gnu
+       #else
+       LIBC=
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+       rm -f $dummy.c && rmdir $tmpdir
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit 0 ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit 0 ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit 0 ;;
+    x86:Interix*:3*)
+       echo i386-pc-interix3
+       exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i386-pc-interix
+       exit 0 ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit 0 ;;
+    arm*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    mips:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips
+       #undef mipsel
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mipsel
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+       rm -f $dummy.c && rmdir $tmpdir
+       test x"${CPU}" != x && echo "${CPU}-pc-linux-gnu" && exit 0
+       ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-gnu
+       exit 0 ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-gnu
+       exit 0 ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+       objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit 0 ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-gnu ;;
+         PA8*) echo hppa2.0-unknown-linux-gnu ;;
+         *)    echo hppa-unknown-linux-gnu ;;
+       esac
+       exit 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux
+       exit 0 ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    x86_64:Linux:*:*)
+       echo x86_64-unknown-linux-gnu
+       exit 0 ;;
+    i*86:Linux:*:*)
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       # Set LC_ALL=C to ensure ld outputs messages in English.
+       ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+                        | sed -ne '/supported targets:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported targets: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_targets" in
+         elf32-i386)
+               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+               ;;
+         a.out-i386-linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit 0 ;;
+         coff-i386)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit 0 ;;
+         "")
+               # Either a pre-BFD a.out linker (linux-gnuoldld) or
+               # one that does not give us useful --help.
+               echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+               exit 0 ;;
+       esac
+       # Determine whether the default compiler is a.out or elf
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <features.h>
+       #ifdef __ELF__
+       # ifdef __GLIBC__
+       #  if __GLIBC__ >= 2
+       LIBC=gnu
+       #  else
+       LIBC=gnulibc1
+       #  endif
+       # else
+       LIBC=gnulibc1
+       # endif
+       #else
+       #ifdef __INTEL_COMPILER
+       LIBC=gnu
+       #else
+       LIBC=gnuaout
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+       rm -f $dummy.c && rmdir $tmpdir
+       test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
+       test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+       ;;
+    i*86:DYNIX/ptx:4*:*)
+       # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+       # earlier versions are messed up and put the nodename in both
+       # sysname and nodename.
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit 0 ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit 0 ;;
+    i*86:*:5:[78]*)
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       exit 0 ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit 0 ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    *:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo hppa1.1-stratus-vos
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit 0 ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit 0 ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Darwin:*:*)
+       echo `uname -p`-apple-darwin${UNAME_RELEASE}
+       exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = "x86"; then
+               UNAME_PROCESSOR=i386
+               UNAME_MACHINE=pc
+       fi
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+       exit 0 ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit 0 ;;
+    NSR-[GKLNPTVW]:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit 0 ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit 0 ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit 0 ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit 0 ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit 0 ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit 0 ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit 0 ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit 0 ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit 0 ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit 0 ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0
+rm -f $dummy.c $dummy && rmdir $tmpdir
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..799b2f0
--- /dev/null
@@ -0,0 +1,129 @@
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define this if you want to include Quick File Access debugging code. */
+#undef DEBUG_QFA
+
+/* Define this if you want to include Mac OSX restore compatibility. */
+#undef DUMP_MACOSX
+
+/* Define this if you have the blkid library. */
+#undef HAVE_BLKID
+
+/* Define this if you have bzlib compression library. */
+#undef HAVE_BZLIB
+
+/* Define to 1 if you have the `err' function. */
+#undef HAVE_ERR
+
+/* Define to 1 if you have the `errx' function. */
+#undef HAVE_ERRX
+
+/* Define to 1 if you have the <ext2fs/ext2_fs.h> header file. */
+#undef HAVE_EXT2FS_EXT2_FS_H
+
+/* Define if we have the ext2_ino_t type (from e2fsprogs 1.20+). */
+#undef HAVE_EXT2_INO_T
+
+/* Define if we have the s_journal_inum field in struct ext2_super_block. */
+#undef HAVE_EXT2_JOURNAL_INUM
+
+/* Define if you have the glob function. */
+#undef HAVE_GLOB
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `lchown' function. */
+#undef HAVE_LCHOWN
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you want to include readline support. */
+#undef HAVE_READLINE
+
+/* Define this if your readline libs have the rl_completion_append_character
+   variable. */
+#undef HAVE_READLINE_CAC
+
+/* Define this if your readline libs have the rl_completion_matches library.
+   */
+#undef HAVE_READLINE_RLCM
+
+/* Define to 1 if you have the `realpath' function. */
+#undef HAVE_REALPATH
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `verr' function. */
+#undef HAVE_VERR
+
+/* Define to 1 if you have the `verrx' function. */
+#undef HAVE_VERRX
+
+/* Define to 1 if you have the `vwarn' function. */
+#undef HAVE_VWARN
+
+/* Define to 1 if you have the `vwarnx' function. */
+#undef HAVE_VWARNX
+
+/* Define to 1 if you have the `warn' function. */
+#undef HAVE_WARN
+
+/* Define to 1 if you have the `warnx' function. */
+#undef HAVE_WARNX
+
+/* Define this if you have zlib compression library. */
+#undef HAVE_ZLIB
+
+/* Define this is you want old style F script (no arguments). */
+#undef OLD_STYLE_FSCRIPT
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define this if you want Large File System support. */
+#undef USE_LFS
+
+/* Define this if you want Quick File Access support. */
+#undef USE_QFA
+
+/* Define to `int64_t' if <sys/types.h> does not define. */
+#undef quad_t
+
+/* Define to `uint64_t' if <sys/types.h> does not define. */
+#undef u_quad_t
diff --git a/config.sub b/config.sub
new file mode 100755 (executable)
index 0000000..9ff085e
--- /dev/null
@@ -0,0 +1,1460 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002 Free Software Foundation, Inc.
+
+timestamp='2002-07-03'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | freebsd*-gnu* | storm-chaos* | os2-emx* | windows32-* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis)
+               os=
+               basic_machine=$1
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       1750a | 580 \
+       | a29k \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+       | c4x | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | fr30 | frv \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k \
+       | m32r | m68000 | m68k | m88k | mcore \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64orion | mips64orionel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | ns16k | ns32k \
+       | openrisc | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+       | pyramid \
+       | sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
+       | strongarm \
+       | tahoe | thumb | tic80 | tron \
+       | v850 | v850e \
+       | we32k \
+       | x86 | xscale | xstormy16 | xtensa \
+       | z8k)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12)
+               # Motorola 68HC11/12.
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       580-* \
+       | a29k-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* \
+       | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c54x-* \
+       | clipper-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | elxsi-* \
+       | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* \
+       | m32r-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | mcore-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipstx39 | mipstx39el \
+       | none-* | np1-* | ns16k-* | ns32k-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+       | pyramid-* \
+       | romp-* | rs6000-* \
+       | sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+       | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+       | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \
+       | v850-* | v850e-* | vax-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+       | xtensa-* \
+       | ymp-* \
+       | z8k-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | j90)
+               basic_machine=j90-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       mingw32)
+               basic_machine=i386-pc
+               os=-mingw32
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       mmix*)
+               basic_machine=mmix-knuth
+               os=-mmixware
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       or32 | or32-*)
+               basic_machine=or32-unknown
+               os=-coff
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+        pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5 | k5 | k6 | nexgen | viac3)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2)
+               basic_machine=i686-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       s390 | s390-*)
+               basic_machine=s390-ibm
+               ;;
+       s390x | s390x-*)
+               basic_machine=s390x-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sparclite-wrs | simso-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+        sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3d)
+               basic_machine=alpha-cray
+               os=-unicos
+               ;;
+       t3e)
+               basic_machine=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
+               os=-unicos
+               ;;
+       tic54x | c54x*)
+               basic_machine=tic54x-unknown
+               os=-coff
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       windows32)
+               basic_machine=i386-pc
+               os=-windows32-msvcrt
+               ;;
+        xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele)
+               basic_machine=sh-unknown
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparc | sparcv9 | sparcv9b)
+               basic_machine=sparc-sun
+               ;;
+        cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       c4x*)
+               basic_machine=c4x-none
+               os=-coff
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* | -powermax*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto*)
+               os=-nto-qnx
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+        -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+       # This must come before the *-dec entry.
+       pdp10-*)
+               os=-tops20
+               ;;
+        pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       or32-*)
+               os=-coff
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+        *-gould)
+               os=-sysv
+               ;;
+        *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+        *-sgi)
+               os=-irix
+               ;;
+        *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..0fb7c6d
--- /dev/null
+++ b/configure
@@ -0,0 +1,6638 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)$' \| \
+        .     : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+         /^X\/\(\/\/\)$/{ s//\1/; q; }
+         /^X\/\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
+  # Find who we are.  Look in the path if we contain no path at all
+  # relative or not.
+  case $0 in
+    *[\\/]* ) as_myself=$0 ;;
+    *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+       ;;
+  esac
+  # We did not find ourselves, most probably we were run as `sh COMMAND'
+  # in which case we are not to be found in the path.
+  if test "x$as_myself" = x; then
+    as_myself=$0
+  fi
+  if test ! -f "$as_myself"; then
+    { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+   { (exit 1); exit 1; }; }
+  fi
+  case $CONFIG_SHELL in
+  '')
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for as_base in sh bash ksh sh5; do
+        case $as_dir in
+        /*)
+          if ("$as_dir/$as_base" -c '
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
+            $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+            $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+            CONFIG_SHELL=$as_dir/$as_base
+            export CONFIG_SHELL
+            exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+          fi;;
+        esac
+       done
+done
+;;
+  esac
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, and appends trailing '-' during
+  # substitution so that $LINENO is not a special case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='     ' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS="  $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete.  It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="dump/dump.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS SET_MAKE LN_S CP MV RM AR ac_ct_AR RANLIB ac_ct_RANLIB PATCH ac_ct_PATCH CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CPP EGREP DUMPDEBUG RESTOREDEBUG STATIC RMTDIR ERMT CRYPTO OPTDEFS READLINE LD CCOPTS LDOPTS BINOWNER BINGRP BINMODE MANOWNER MANGRP MANMODE DUMPDATESPATH BLKID ZLIB BZLIB top_builddir LIBOBJS LTLIBOBJS'
+ac_subst_files='MCONFIG'
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_option in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    eval "enable_$ac_feature=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_$ac_feature='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_$ac_package='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/-/_/g'`
+    eval "with_$ac_package=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+    eval "$ac_envvar='$ac_optarg'"
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+             localstatedir libdir includedir oldincludedir infodir mandir
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$0" : 'X\(//\)[^/]' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| \
+        .     : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+         /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+         /^X\(\/\/\)$/{ s//\1/; q; }
+         /^X\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+   { (exit 1); exit 1; }; }
+  else
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+  fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+  { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+   { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+  cat <<_ACEOF
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                         [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                         [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --datadir=DIR          read-only architecture-independent data [PREFIX/share]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --infodir=DIR          info documentation [PREFIX/info]
+  --mandir=DIR           man documentation [PREFIX/man]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-debug             include debugging code (default is NO)
+  --enable-static            link dump and restore statically (default is NO)
+  --enable-staticz           link libz and libbz2 statically (default is NO)
+  --enable-rmt               compile and install rmt (default is YES)
+  --enable-ermt              compile ermt, an encrypting version of rmt (default is NO)
+  --enable-kerberos          compile kerberos extensions (default is NO)
+  --enable-readline          enable readline support in restore (default is YES)
+  --enable-oldstylefscript   enable old style F script (no arguments) (default is NO)
+  --enable-largefile         enable Large File System support (default is YES)
+  --enable-qfa               enable Quick File Access support (default is YES)
+  --enable-qfadebug          include Quick File Access debugging code (default is NO)
+  --enable-macosx            include Mac OSX restore compatibility (default is NO)
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-cc=COMPILER         select compiler to use
+  --with-linker=LINKER       select linker to use
+  --with-ccopts=CCOPTS       select compiler command line options
+  --with-ldopts=LDOPTS       select linker command line options
+  --with-binowner=USER       select owner for binaries
+  --with-bingrp=GROUP        select group for binaries
+  --with-binmode=MODE        select mode for binaries
+  --with-manowner=USER       select owner for manual pages
+  --with-mangrp=GROUP        select group for manual pages
+  --with-manmode=MODE        select mode for manual pages
+  --with-dumpdatespath=PATH  select path for dumpdates file
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  CPPFLAGS    C/C++ preprocessor flags, e.g. -I<include dir> if you have
+              headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  ac_popdir=`pwd`
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d $ac_dir || continue
+    ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+  case "$ac_dir" in
+  .) ac_abs_builddir=`pwd`;;
+  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+  *) ac_abs_builddir=`pwd`/"$ac_dir";;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+  case ${ac_top_builddir}. in
+  .) ac_abs_top_builddir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+  case $ac_srcdir in
+  .) ac_abs_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+  case $ac_top_srcdir in
+  .) ac_abs_top_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+  esac;;
+esac
+
+    cd $ac_dir
+    # Check for guested configure; otherwise get Cygnus style configure.
+    if test -f $ac_srcdir/configure.gnu; then
+      echo
+      $SHELL $ac_srcdir/configure.gnu  --help=recursive
+    elif test -f $ac_srcdir/configure; then
+      echo
+      $SHELL $ac_srcdir/configure  --help=recursive
+    elif test -f $ac_srcdir/configure.ac ||
+          test -f $ac_srcdir/configure.in; then
+      echo
+      $ac_configure --help
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi
+    cd $ac_popdir
+  done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+  cat <<\_ACEOF
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.59.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo               = `(hostinfo) 2>/dev/null               || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *" "*|*"   "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+      # Get rid of the leading space.
+      ac_sep=" "
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+{
+  (set) 2>&1 |
+    case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+    *ac_space=\ *)
+      sed -n \
+       "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+      ;;
+    *)
+      sed -n \
+       "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+}
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=$`echo $ac_var`
+      echo "$ac_var='"'"'$ac_val'"'"'"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=$`echo $ac_var`
+       echo "$ac_var='"'"'$ac_val'"'"'"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      sed "/^$/d" confdefs.h | sort
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core &&
+  rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+     ' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . $cache_file;;
+      *)                      . ./$cache_file;;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+              sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+  eval ac_new_val="\$ac_env_${ac_var}_value"
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+       { echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+       { echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+       ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *" "*|*"   "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+      ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+MCONFIG=./MCONFIG
+
+
+          ac_config_headers="$ac_config_headers config.h"
+
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.make <<\_ACEOF
+all:
+       @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+  SET_MAKE=
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+  echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6
+fi
+
+# Extract the first word of "cp", so it can be a program name with args.
+set dummy cp; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_CP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $CP in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_CP="$CP" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_CP="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_path_CP" && ac_cv_path_CP="cp"
+  ;;
+esac
+fi
+CP=$ac_cv_path_CP
+
+if test -n "$CP"; then
+  echo "$as_me:$LINENO: result: $CP" >&5
+echo "${ECHO_T}$CP" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "mv", so it can be a program name with args.
+set dummy mv; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_MV+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $MV in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_MV="$MV" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_MV="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_path_MV" && ac_cv_path_MV="mv"
+  ;;
+esac
+fi
+MV=$ac_cv_path_MV
+
+if test -n "$MV"; then
+  echo "$as_me:$LINENO: result: $MV" >&5
+echo "${ECHO_T}$MV" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+# Extract the first word of "rm", so it can be a program name with args.
+set dummy rm; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_RM+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $RM in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_RM="$RM" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_path_RM" && ac_cv_path_RM="rm"
+  ;;
+esac
+fi
+RM=$ac_cv_path_RM
+
+if test -n "$RM"; then
+  echo "$as_me:$LINENO: result: $RM" >&5
+echo "${ECHO_T}$RM" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="${ac_tool_prefix}ar"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+  ac_ct_AR=$AR
+  # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="ar"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="ar"
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  AR=$ac_ct_AR
+else
+  AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  RANLIB=$ac_ct_RANLIB
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}patch", so it can be a program name with args.
+set dummy ${ac_tool_prefix}patch; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_PATCH+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$PATCH"; then
+  ac_cv_prog_PATCH="$PATCH" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_PATCH="${ac_tool_prefix}patch"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+PATCH=$ac_cv_prog_PATCH
+if test -n "$PATCH"; then
+  echo "$as_me:$LINENO: result: $PATCH" >&5
+echo "${ECHO_T}$PATCH" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_PATCH"; then
+  ac_ct_PATCH=$PATCH
+  # Extract the first word of "patch", so it can be a program name with args.
+set dummy patch; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_PATCH+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_PATCH"; then
+  ac_cv_prog_ac_ct_PATCH="$ac_ct_PATCH" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_PATCH="patch"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_PATCH" && ac_cv_prog_ac_ct_PATCH=":"
+fi
+fi
+ac_ct_PATCH=$ac_cv_prog_ac_ct_PATCH
+if test -n "$ac_ct_PATCH"; then
+  echo "$as_me:$LINENO: result: $ac_ct_PATCH" >&5
+echo "${ECHO_T}$ac_ct_PATCH" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  PATCH=$ac_ct_PATCH
+else
+  PATCH="$ac_cv_prog_PATCH"
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$ac_ct_CC" && break
+done
+
+  CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+     "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+  (eval $ac_compiler --version </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+  (eval $ac_compiler -v </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+  (eval $ac_compiler -V </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+  (eval $ac_link_default) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Find the output, starting from the most likely.  This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+       ;;
+    conftest.$ac_ext )
+       # This is the source file.
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+       ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       # FIXME: I believe we export ac_cv_exeext for Libtool,
+       # but it would be cool to find out if it's true.  Does anybody
+       # maintain Libtool? --akim.
+       export ac_cv_exeext
+       break;;
+    * )
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         export ac_cv_exeext
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std1 is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std1.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX                  -qlanglvl=ansi
+# Ultrix and OSF/1     -std1
+# HP-UX 10.20 and later        -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4                 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno)
+    echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+  *)
+    echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+    CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C.  Since we use `exit',
+# in C++ we need to declare it.  In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+  choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  for ac_declaration in \
+   '' \
+   'extern "C" void std::exit (int) throw (); using std::exit;' \
+   'extern "C" void std::exit (int); using std::exit;' \
+   'extern "C" void exit (int) throw ();' \
+   'extern "C" void exit (int);' \
+   'void exit (int);'
+do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+  echo '#ifdef __cplusplus' >>confdefs.h
+  echo $ac_declaration      >>confdefs.h
+  echo '#endif'             >>confdefs.h
+fi
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f $ac_dir/shtool; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+           break 3
+         fi
+       fi
+      done
+    done
+    ;;
+esac
+done
+
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL=$ac_install_sh
+  fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether non-existent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether non-existent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      exit(2);
+  exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in sys/types.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+CPPFLAGS="-D_BSD_SOURCE -D_USE_BSD_SIGNAL ${CPPFLAGS}"
+
+# Check whether --enable-debug or --disable-debug was given.
+if test "${enable_debug+set}" = set; then
+  enableval="$enable_debug"
+  if test "$enableval" = "no"
+then
+       DUMPDEBUG=""
+       RESTOREDEBUG=""
+       echo "Not including debugging code"
+else
+       DUMPDEBUG="-DFDEBUG -DTDEBUG -DWRITEDEBUG -DDIRDEBUG"
+       RESTOREDEBUG="-DDIRDEBUG"
+       echo "Including debugging code"
+fi
+else
+  DUMPDEBUG=""
+RESTOREDEBUG=""
+echo "Not including debugging code by default"
+
+fi;
+
+
+
+# Check whether --enable-static or --disable-static was given.
+if test "${enable_static+set}" = set; then
+  enableval="$enable_static"
+  if test "$enableval" = "no"
+then
+       STATIC=""
+       echo "Linking dump and restore dynamically"
+else
+       STATIC="-static"
+       echo "Linking dump and restore statically"
+fi
+
+else
+  STATIC=""
+echo "Linking dump and restore dynamically by default"
+
+fi;
+
+
+# Check whether --enable-staticz or --disable-staticz was given.
+if test "${enable_staticz+set}" = set; then
+  enableval="$enable_staticz"
+  if test "$enableval" = "no"
+then
+       STATICZ="no"
+       echo "Linking libz and libbz2 dynamically"
+else
+       STATICZ="yes"
+       echo "Linking libz and libbz2 statically"
+fi
+
+else
+  STATICZ="no"
+echo "Linking libz and libbz2 dynamically by default"
+
+fi;
+
+# Check whether --enable-rmt or --disable-rmt was given.
+if test "${enable_rmt+set}" = set; then
+  enableval="$enable_rmt"
+  if test "$enableval" = "no"
+then
+       RMTDIR=""
+       RMTMAKEFILE=""
+       echo "Not compiling rmt"
+else
+       RMTDIR="rmt"
+       RMTMAKEFILE="rmt/Makefile"
+       echo "Compiling rmt"
+fi
+
+else
+  RMTDIR="rmt"
+RMTMAKEFILE="rmt/Makefile"
+echo "Compiling rmt by default"
+
+fi;
+
+
+# Check whether --enable-ermt or --disable-ermt was given.
+if test "${enable_ermt+set}" = set; then
+  enableval="$enable_ermt"
+  if test "$enableval" = "no"
+then
+       ERMT=""
+       CRYPTO=""
+       echo "Not compiling ermt"
+else
+       if test "$RMTDIR" = ""
+       then
+               { { echo "$as_me:$LINENO: error: ermt requires --enable-rmt" >&5
+echo "$as_me: error: ermt requires --enable-rmt" >&2;}
+   { (exit 1); exit 1; }; }
+       fi
+       ERMT="ermt"
+       CRYPTO="-lcrypto"
+       echo "Compiling ermt"
+fi
+
+else
+  ERMT=""
+CRYPTO=""
+echo "Not compiling ermt by default"
+
+fi;
+
+
+
+# Check whether --enable-kerberos or --disable-kerberos was given.
+if test "${enable_kerberos+set}" = set; then
+  enableval="$enable_kerberos"
+  if test "$enableval" = "yes"
+then
+       OPTDEFS="-DKERBEROS"
+       echo "Compiling kerberos extensions"
+else
+       OPTDEFS=""
+       echo "Not compiling kerberos extensions"
+fi
+
+else
+  OPTDEFS=""
+echo "Not compiling kerberos extensions by default"
+
+fi;
+
+
+# Check whether --enable-readline or --disable-readline was given.
+if test "${enable_readline+set}" = set; then
+  enableval="$enable_readline"
+  if test "$enableval" = "no"
+then
+       READLINE=""
+       echo "Not including readline support"
+else
+       READLINE="-lreadline -ltermcap"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_READLINE 1
+_ACEOF
+
+       echo "Including readline support"
+fi
+
+else
+  READLINE="-lreadline -ltermcap"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_READLINE 1
+_ACEOF
+
+echo "Including readline support by default"
+
+fi;
+
+
+# Check whether --enable-oldstylefscript or --disable-oldstylefscript was given.
+if test "${enable_oldstylefscript+set}" = set; then
+  enableval="$enable_oldstylefscript"
+  if test "$enableval" = "yes"
+then
+
+cat >>confdefs.h <<\_ACEOF
+#define OLD_STYLE_FSCRIPT 1
+_ACEOF
+
+       echo "Using old style F script"
+else
+       echo "Using new style F script"
+fi
+
+else
+  echo "Using new style F script by default"
+
+fi;
+
+# Check whether --enable-largefile or --disable-largefile was given.
+if test "${enable_largefile+set}" = set; then
+  enableval="$enable_largefile"
+  if test "$enableval" = "yes"
+then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_LFS 1
+_ACEOF
+
+       echo "Enabling Large File System support"
+else
+       echo "Not enabling Large File System support"
+fi
+
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_LFS 1
+_ACEOF
+
+echo "Enabling Large File System support by default"
+
+fi;
+
+# Check whether --enable-qfa or --disable-qfa was given.
+if test "${enable_qfa+set}" = set; then
+  enableval="$enable_qfa"
+  if test "$enableval" = "yes"
+then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_QFA 1
+_ACEOF
+
+       echo "Enabling Quick File Access support"
+else
+       echo "Not enabling Quick File Access support"
+fi
+
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_QFA 1
+_ACEOF
+
+echo "Enabling Quick File Access support by default"
+
+fi;
+
+# Check whether --enable-qfadebug or --disable-qfadebug was given.
+if test "${enable_qfadebug+set}" = set; then
+  enableval="$enable_qfadebug"
+  if test "$enableval" = "yes"
+then
+
+cat >>confdefs.h <<\_ACEOF
+#define DEBUG_QFA 1
+_ACEOF
+
+       echo "Including Quick File Access debugging code"
+else
+       echo "Not including Quick File Access debugging code"
+fi
+
+else
+  echo "Not including Quick File Access debugging code by default"
+
+fi;
+
+# Check whether --enable-macosx or --disable-macosx was given.
+if test "${enable_macosx+set}" = set; then
+  enableval="$enable_macosx"
+  if test "$enableval" = "yes"
+then
+
+cat >>confdefs.h <<\_ACEOF
+#define DUMP_MACOSX 1
+_ACEOF
+
+       echo "Including Mac OSX restore compatibility code"
+else
+       echo "Not including Mac OSX restore compatibility code"
+fi
+
+else
+  echo "Not including Mac OSX restore compatibility code by default"
+
+fi;
+
+
+
+# Check whether --with-cc or --without-cc was given.
+if test "${with_cc+set}" = set; then
+  withval="$with_cc"
+  echo "$as_me:$LINENO: result: CC=$withval" >&5
+echo "${ECHO_T}CC=$withval" >&6
+CC=$withval
+else
+  if test -z "$CC" ; then CC=cc; fi
+echo "$as_me:$LINENO: result: CC defaults to $CC" >&5
+echo "${ECHO_T}CC defaults to $CC" >&6
+fi; export CC
+
+
+
+# Check whether --with-linker or --without-linker was given.
+if test "${with_linker+set}" = set; then
+  withval="$with_linker"
+  echo "$as_me:$LINENO: result: LD=$withval" >&5
+echo "${ECHO_T}LD=$withval" >&6
+LD=$withval
+else
+  if test -z "$LD" ; then LD=$CC; fi
+echo "$as_me:$LINENO: result: LD defaults to $LD" >&5
+echo "${ECHO_T}LD defaults to $LD" >&6
+fi; export LD
+
+
+
+# Check whether --with-ccopts or --without-ccopts was given.
+if test "${with_ccopts+set}" = set; then
+  withval="$with_ccopts"
+  echo "$as_me:$LINENO: result: CCOPTS is $withval" >&5
+echo "${ECHO_T}CCOPTS is $withval" >&6
+CCOPTS=$withval
+CFLAGS="$CFLAGS $withval"
+else
+  CCOPTS=
+fi;
+
+
+# Check whether --with-ldopts or --without-ldopts was given.
+if test "${with_ldopts+set}" = set; then
+  withval="$with_ldopts"
+  echo "$as_me:$LINENO: result: LDFLAGS is $withval" >&5
+echo "${ECHO_T}LDFLAGS is $withval" >&6
+LDOPTS=$withval
+LDFLAGS="$LDFLAGS $withval"
+else
+  LDOPTS=
+fi;
+
+
+# Check whether --with-binowner or --without-binowner was given.
+if test "${with_binowner+set}" = set; then
+  withval="$with_binowner"
+  echo "$as_me:$LINENO: result: BINOWNER is $withval" >&5
+echo "${ECHO_T}BINOWNER is $withval" >&6
+BINOWNER=$withval
+else
+  BINOWNER=root
+echo "BINOWNER defaults to $BINOWNER"
+
+fi;
+
+
+# Check whether --with-bingrp or --without-bingrp was given.
+if test "${with_bingrp+set}" = set; then
+  withval="$with_bingrp"
+  echo "$as_me:$LINENO: result: BINGRP is $withval" >&5
+echo "${ECHO_T}BINGRP is $withval" >&6
+BINGRP=$withval
+else
+  BINGRP=tty
+echo "BINGRP defaults to $BINGRP"
+
+fi;
+
+
+# Check whether --with-binmode or --without-binmode was given.
+if test "${with_binmode+set}" = set; then
+  withval="$with_binmode"
+  echo "$as_me:$LINENO: result: BINMODE is $withval" >&5
+echo "${ECHO_T}BINMODE is $withval" >&6
+BINMODE=$withval
+else
+  BINMODE=0755
+echo "BINMODE defaults to $BINMODE"
+
+fi;
+
+
+# Check whether --with-manowner or --without-manowner was given.
+if test "${with_manowner+set}" = set; then
+  withval="$with_manowner"
+  echo "$as_me:$LINENO: result: MANOWNER is $withval" >&5
+echo "${ECHO_T}MANOWNER is $withval" >&6
+MANOWNER=$withval
+else
+  MANOWNER=man
+echo "MANOWNER defaults to $MANOWNER"
+
+fi;
+
+
+# Check whether --with-mangrp or --without-mangrp was given.
+if test "${with_mangrp+set}" = set; then
+  withval="$with_mangrp"
+  echo "$as_me:$LINENO: result: MANGRP is $withval" >&5
+echo "${ECHO_T}MANGRP is $withval" >&6
+MANGRP=$withval
+else
+  MANGRP=tty
+echo "MANGRP defaults to $MANGRP"
+
+fi;
+
+
+# Check whether --with-manmode or --without-manmode was given.
+if test "${with_manmode+set}" = set; then
+  withval="$with_manmode"
+  echo "$as_me:$LINENO: result: MANMODE is $withval" >&5
+echo "${ECHO_T}MANMODE is $withval" >&6
+MANMODE=$withval
+else
+  MANMODE=0644
+echo "MANMODE defaults to $MANMODE"
+
+fi;
+
+
+# Check whether --with-dumpdatespath or --without-dumpdatespath was given.
+if test "${with_dumpdatespath+set}" = set; then
+  withval="$with_dumpdatespath"
+  echo "$as_me:$LINENO: result: DUMPDATESPATH is $withval" >&5
+echo "${ECHO_T}DUMPDATESPATH is $withval" >&6
+DUMPDATESPATH=$withval
+else
+  DUMPDATESPATH="${sysconfdir}/dumpdates"
+echo "DUMPDATESPATH defaults to $DUMPDATESPATH"
+
+fi;
+
+echo "$as_me:$LINENO: checking for ext2fs/ext2fs.h" >&5
+echo $ECHO_N "checking for ext2fs/ext2fs.h... $ECHO_C" >&6
+if test "${ac_cv_header_ext2fs_ext2fs_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ext2fs/ext2fs.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_cv_header_ext2fs_ext2fs_h=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_cv_header_ext2fs_ext2fs_h=no
+fi
+rm -f conftest.err conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_ext2fs_ext2fs_h" >&5
+echo "${ECHO_T}$ac_cv_header_ext2fs_ext2fs_h" >&6
+if test $ac_cv_header_ext2fs_ext2fs_h = yes; then
+  ext2fs_h=yes
+else
+  ext2fs_h=no
+fi
+
+
+echo "$as_me:$LINENO: checking for ext2fs_open in -lext2fs" >&5
+echo $ECHO_N "checking for ext2fs_open in -lext2fs... $ECHO_C" >&6
+if test "${ac_cv_lib_ext2fs_ext2fs_open+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lext2fs -lcom_err $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char ext2fs_open ();
+int
+main ()
+{
+ext2fs_open ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_ext2fs_ext2fs_open=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_ext2fs_ext2fs_open=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_ext2fs_ext2fs_open" >&5
+echo "${ECHO_T}$ac_cv_lib_ext2fs_ext2fs_open" >&6
+if test $ac_cv_lib_ext2fs_ext2fs_open = yes; then
+  ext2fs_lib=yes
+else
+  ext2fs_lib=no
+fi
+
+if test "$ext2fs_h" = no -o "$ext2fs_lib" = no; then
+       { { echo "$as_me:$LINENO: error: You need to install the Ext2fs libraries from the E2fsprogs distribution first - hint: make install-libs" >&5
+echo "$as_me: error: You need to install the Ext2fs libraries from the E2fsprogs distribution first - hint: make install-libs" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+for ac_header in ext2fs/ext2_fs.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking for ext2_ino_t type in libext2fs headers" >&5
+echo $ECHO_N "checking for ext2_ino_t type in libext2fs headers... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdio.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>
+int
+main ()
+{
+ext2_ino_t ino = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_EXT2_INO_T 1
+_ACEOF
+
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking for s_journal_inum field in ext2_super_block struct" >&5
+echo $ECHO_N "checking for s_journal_inum field in ext2_super_block struct... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdio.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>
+int
+main ()
+{
+struct ext2_super_block es; es.s_journal_inum = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_EXT2_JOURNAL_INUM 1
+_ACEOF
+
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+echo "$as_me:$LINENO: checking for blkid/blkid.h" >&5
+echo $ECHO_N "checking for blkid/blkid.h... $ECHO_C" >&6
+if test "${ac_cv_header_blkid_blkid_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <blkid/blkid.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_cv_header_blkid_blkid_h=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_cv_header_blkid_blkid_h=no
+fi
+rm -f conftest.err conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_blkid_blkid_h" >&5
+echo "${ECHO_T}$ac_cv_header_blkid_blkid_h" >&6
+if test $ac_cv_header_blkid_blkid_h = yes; then
+  blkid_h=yes
+else
+  blkid_h=no
+fi
+
+
+echo "$as_me:$LINENO: checking for blkid_get_devname in -lblkid" >&5
+echo $ECHO_N "checking for blkid_get_devname in -lblkid... $ECHO_C" >&6
+if test "${ac_cv_lib_blkid_blkid_get_devname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lblkid -luuid $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char blkid_get_devname ();
+int
+main ()
+{
+blkid_get_devname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_blkid_blkid_get_devname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_blkid_blkid_get_devname=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_blkid_blkid_get_devname" >&5
+echo "${ECHO_T}$ac_cv_lib_blkid_blkid_get_devname" >&6
+if test $ac_cv_lib_blkid_blkid_get_devname = yes; then
+  blkid_lib=yes
+else
+  blkid_lib=no
+fi
+
+if test "$blkid_h" = yes -a "$blkid_lib" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_BLKID 1
+_ACEOF
+
+       BLKID="-lblkid -luuid"
+fi
+
+
+echo "$as_me:$LINENO: checking for tgetent in -ltermcap" >&5
+echo $ECHO_N "checking for tgetent in -ltermcap... $ECHO_C" >&6
+if test "${ac_cv_lib_termcap_tgetent+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ltermcap  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char tgetent ();
+int
+main ()
+{
+tgetent ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_termcap_tgetent=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_termcap_tgetent=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_termcap_tgetent" >&5
+echo "${ECHO_T}$ac_cv_lib_termcap_tgetent" >&6
+if test $ac_cv_lib_termcap_tgetent = yes; then
+  termcap_lib=yes
+else
+  termcap_lib=no
+fi
+
+if test "$termcap_lib" = no; then
+       if test "$READLINE" = "-lreadline -ltermcap"; then
+               { { echo "$as_me:$LINENO: error: You need to install the GNU termcap library or configure without --enable-readline" >&5
+echo "$as_me: error: You need to install the GNU termcap library or configure without --enable-readline" >&2;}
+   { (exit 1); exit 1; }; }
+       fi
+fi
+
+echo "$as_me:$LINENO: checking for readline/readline.h" >&5
+echo $ECHO_N "checking for readline/readline.h... $ECHO_C" >&6
+if test "${ac_cv_header_readline_readline_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <readline/readline.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_cv_header_readline_readline_h=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_cv_header_readline_readline_h=no
+fi
+rm -f conftest.err conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_readline_readline_h" >&5
+echo "${ECHO_T}$ac_cv_header_readline_readline_h" >&6
+if test $ac_cv_header_readline_readline_h = yes; then
+  readline_h=yes
+else
+  readline_h=no
+fi
+
+
+echo "$as_me:$LINENO: checking for readline in -lreadline" >&5
+echo $ECHO_N "checking for readline in -lreadline... $ECHO_C" >&6
+if test "${ac_cv_lib_readline_readline+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lreadline "-ltermcap" $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char readline ();
+int
+main ()
+{
+readline ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_readline_readline=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_readline_readline=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_readline_readline" >&5
+echo "${ECHO_T}$ac_cv_lib_readline_readline" >&6
+if test $ac_cv_lib_readline_readline = yes; then
+  readline_lib=yes
+else
+  readline_lib=no
+fi
+
+if test "$readline_h" = no -o "$readline_lib" = no; then
+       if test "$READLINE" = "-lreadline -ltermcap"; then
+               { { echo "$as_me:$LINENO: error: You need to install the GNU readline library or configure without --enable-readline" >&5
+echo "$as_me: error: You need to install the GNU readline library or configure without --enable-readline" >&2;}
+   { (exit 1); exit 1; }; }
+       fi
+fi
+
+echo "$as_me:$LINENO: checking for rl_completion_matches in -lreadline" >&5
+echo $ECHO_N "checking for rl_completion_matches in -lreadline... $ECHO_C" >&6
+if test "${ac_cv_lib_readline_rl_completion_matches+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lreadline "-ltermcap" $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char rl_completion_matches ();
+int
+main ()
+{
+rl_completion_matches ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_readline_rl_completion_matches=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_readline_rl_completion_matches=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_readline_rl_completion_matches" >&5
+echo "${ECHO_T}$ac_cv_lib_readline_rl_completion_matches" >&6
+if test $ac_cv_lib_readline_rl_completion_matches = yes; then
+  rlcm=yes
+else
+  rlcm=no
+fi
+
+if test "$rlcm" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_READLINE_RLCM 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for rl_completion_append_character in -lreadline" >&5
+echo $ECHO_N "checking for rl_completion_append_character in -lreadline... $ECHO_C" >&6
+if test "${ac_cv_lib_readline_rl_completion_append_character+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lreadline "-ltermcap" $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char rl_completion_append_character ();
+int
+main ()
+{
+rl_completion_append_character ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_readline_rl_completion_append_character=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_readline_rl_completion_append_character=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_readline_rl_completion_append_character" >&5
+echo "${ECHO_T}$ac_cv_lib_readline_rl_completion_append_character" >&6
+if test $ac_cv_lib_readline_rl_completion_append_character = yes; then
+  rcac=yes
+else
+  rcac=no
+fi
+
+if test "$rcac" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_READLINE_CAC 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for zlib.h" >&5
+echo $ECHO_N "checking for zlib.h... $ECHO_C" >&6
+if test "${ac_cv_header_zlib_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <zlib.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_cv_header_zlib_h=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_cv_header_zlib_h=no
+fi
+rm -f conftest.err conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_zlib_h" >&5
+echo "${ECHO_T}$ac_cv_header_zlib_h" >&6
+if test $ac_cv_header_zlib_h = yes; then
+  zlib_h=yes
+else
+  zlib_h=no
+fi
+
+
+echo "$as_me:$LINENO: checking for compress2 in -lz" >&5
+echo $ECHO_N "checking for compress2 in -lz... $ECHO_C" >&6
+if test "${ac_cv_lib_z_compress2+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char compress2 ();
+int
+main ()
+{
+compress2 ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_z_compress2=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_z_compress2=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_z_compress2" >&5
+echo "${ECHO_T}$ac_cv_lib_z_compress2" >&6
+if test $ac_cv_lib_z_compress2 = yes; then
+  zlib_lib=yes
+else
+  zlib_lib=no
+fi
+
+if test "$zlib_h" = yes -a "$zlib_lib" = yes; then
+       if test "$STATICZ" = yes; then
+               ZLIB="-Wl,-Bstatic -lz -Wl,-Bdynamic"
+       else
+               ZLIB="-lz"
+       fi
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ZLIB 1
+_ACEOF
+
+else
+       ZLIB=""
+fi
+
+
+echo "$as_me:$LINENO: checking for bzlib.h" >&5
+echo $ECHO_N "checking for bzlib.h... $ECHO_C" >&6
+if test "${ac_cv_header_bzlib_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <bzlib.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_cv_header_bzlib_h=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_cv_header_bzlib_h=no
+fi
+rm -f conftest.err conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_bzlib_h" >&5
+echo "${ECHO_T}$ac_cv_header_bzlib_h" >&6
+if test $ac_cv_header_bzlib_h = yes; then
+  bzlib_h=yes
+else
+  bzlib_h=no
+fi
+
+
+echo "$as_me:$LINENO: checking for BZ2_bzBuffToBuffCompress in -lbz2" >&5
+echo $ECHO_N "checking for BZ2_bzBuffToBuffCompress in -lbz2... $ECHO_C" >&6
+if test "${ac_cv_lib_bz2_BZ2_bzBuffToBuffCompress+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbz2  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char BZ2_bzBuffToBuffCompress ();
+int
+main ()
+{
+BZ2_bzBuffToBuffCompress ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_bz2_BZ2_bzBuffToBuffCompress=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_bz2_BZ2_bzBuffToBuffCompress=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_bz2_BZ2_bzBuffToBuffCompress" >&5
+echo "${ECHO_T}$ac_cv_lib_bz2_BZ2_bzBuffToBuffCompress" >&6
+if test $ac_cv_lib_bz2_BZ2_bzBuffToBuffCompress = yes; then
+  bzlib_lib=yes
+else
+  bzlib_lib=no
+fi
+
+if test "$bzlib_h" = yes -a "$bzlib_lib" = yes; then
+       if test "$STATICZ" = yes; then
+               BZLIB="-Wl,-Bstatic -lbz2 -Wl,-Bdynamic"
+       else
+               BZLIB="-lbz2"
+       fi
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_BZLIB 1
+_ACEOF
+
+else
+       BZLIB=""
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in err errx verr verrx vwarn vwarnx warn warnx realpath lchown
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+echo "$as_me:$LINENO: checking for glob" >&5
+echo $ECHO_N "checking for glob... $ECHO_C" >&6
+if test "${ac_cv_func_glob+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define glob to an innocuous variant, in case <limits.h> declares glob.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define glob innocuous_glob
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char glob (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef glob
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char glob ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_glob) || defined (__stub___glob)
+choke me
+#else
+char (*f) () = glob;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != glob;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_glob=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_glob=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_glob" >&5
+echo "${ECHO_T}$ac_cv_func_glob" >&6
+
+
+echo "$as_me:$LINENO: checking for extended glob routines" >&5
+echo $ECHO_N "checking for extended glob routines... $ECHO_C" >&6
+if test "$ac_cv_func_glob" = "yes"; then
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#      include <glob.h>
+#      ifdef GLOB_ALTDIRFUNC
+       yes
+#      endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "yes" >/dev/null 2>&1; then
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GLOB 1
+_ACEOF
+
+       echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+else
+
+       echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+       echo "Your system does not support extended glob, will use the internal routines"
+
+fi
+rm -f conftest*
+
+fi
+
+if test "$ERMT" != ""; then
+       if test "${ac_cv_header_openssl_evp_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for openssl/evp.h" >&5
+echo $ECHO_N "checking for openssl/evp.h... $ECHO_C" >&6
+if test "${ac_cv_header_openssl_evp_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_openssl_evp_h" >&5
+echo "${ECHO_T}$ac_cv_header_openssl_evp_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking openssl/evp.h usability" >&5
+echo $ECHO_N "checking openssl/evp.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <openssl/evp.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking openssl/evp.h presence" >&5
+echo $ECHO_N "checking openssl/evp.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <openssl/evp.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: openssl/evp.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: openssl/evp.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/evp.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: openssl/evp.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: openssl/evp.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: openssl/evp.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/evp.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: openssl/evp.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/evp.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: openssl/evp.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/evp.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: openssl/evp.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/evp.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: openssl/evp.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/evp.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: openssl/evp.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for openssl/evp.h" >&5
+echo $ECHO_N "checking for openssl/evp.h... $ECHO_C" >&6
+if test "${ac_cv_header_openssl_evp_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_openssl_evp_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_openssl_evp_h" >&5
+echo "${ECHO_T}$ac_cv_header_openssl_evp_h" >&6
+
+fi
+if test $ac_cv_header_openssl_evp_h = yes; then
+  evp_h=yes
+else
+  evp_h=no
+fi
+
+
+       echo "$as_me:$LINENO: checking for EVP_CIPHER_CTX_set_padding in -lcrypto" >&5
+echo $ECHO_N "checking for EVP_CIPHER_CTX_set_padding in -lcrypto... $ECHO_C" >&6
+if test "${ac_cv_lib_crypto_EVP_CIPHER_CTX_set_padding+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypto  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char EVP_CIPHER_CTX_set_padding ();
+int
+main ()
+{
+EVP_CIPHER_CTX_set_padding ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_crypto_EVP_CIPHER_CTX_set_padding=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_crypto_EVP_CIPHER_CTX_set_padding=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_EVP_CIPHER_CTX_set_padding" >&5
+echo "${ECHO_T}$ac_cv_lib_crypto_EVP_CIPHER_CTX_set_padding" >&6
+if test $ac_cv_lib_crypto_EVP_CIPHER_CTX_set_padding = yes; then
+  crypto_lib=yes
+else
+  crypto_lib=no
+fi
+
+       if test "$evp_h" = no -o "$crypto_lib" = no; then
+               { { echo "$as_me:$LINENO: error: You need to install the OpenSSL library (version 0.9.7a or later)" >&5
+echo "$as_me: error: You need to install the OpenSSL library (version 0.9.7a or later)" >&2;}
+   { (exit or configure without --enable-ermt); exit or configure without --enable-ermt; }; }
+       fi
+fi
+
+echo "$as_me:$LINENO: checking for quad_t" >&5
+echo $ECHO_N "checking for quad_t... $ECHO_C" >&6
+if test "${ac_cv_type_quad_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+if ((quad_t *) 0)
+  return 0;
+if (sizeof (quad_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_quad_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_quad_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_quad_t" >&5
+echo "${ECHO_T}$ac_cv_type_quad_t" >&6
+if test $ac_cv_type_quad_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define quad_t int64_t
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for u_quad_t" >&5
+echo $ECHO_N "checking for u_quad_t... $ECHO_C" >&6
+if test "${ac_cv_type_u_quad_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+if ((u_quad_t *) 0)
+  return 0;
+if (sizeof (u_quad_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_u_quad_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_u_quad_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_u_quad_t" >&5
+echo "${ECHO_T}$ac_cv_type_u_quad_t" >&6
+if test $ac_cv_type_u_quad_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define u_quad_t uint64_t
+_ACEOF
+
+fi
+
+
+top_builddir=`cd .; pwd`
+
+
+test -d compat || mkdir compat
+test -d compat/lib || mkdir compat/lib
+
+                                                                                ac_config_files="$ac_config_files MCONFIG Makefile common/Makefile compat/include/Makefile compat/lib/Makefile dump/Makefile restore/Makefile $RMTMAKEFILE"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+  (set) 2>&1 |
+    case `(ac_space=' '; set | grep ac_space) 2>&1` in
+    *ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;;
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n \
+       "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+} |
+  sed '
+     t clear
+     : clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+  if test -w $cache_file; then
+    test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+    cat confcache >$cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[    ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[      ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_i=`echo "$ac_i" |
+        sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+  # 2. Add them.
+  ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)$' \| \
+        .     : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+         /^X\/\(\/\/\)$/{ s//\1/; q; }
+         /^X\/\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
+  # Find who we are.  Look in the path if we contain no path at all
+  # relative or not.
+  case $0 in
+    *[\\/]* ) as_myself=$0 ;;
+    *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+       ;;
+  esac
+  # We did not find ourselves, most probably we were run as `sh COMMAND'
+  # in which case we are not to be found in the path.
+  if test "x$as_myself" = x; then
+    as_myself=$0
+  fi
+  if test ! -f "$as_myself"; then
+    { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+  case $CONFIG_SHELL in
+  '')
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for as_base in sh bash ksh sh5; do
+        case $as_dir in
+        /*)
+          if ("$as_dir/$as_base" -c '
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
+            $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+            $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+            CONFIG_SHELL=$as_dir/$as_base
+            export CONFIG_SHELL
+            exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+          fi;;
+        esac
+       done
+done
+;;
+  esac
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, and appends trailing '-' during
+  # substitution so that $LINENO is not a special case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='     ' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS="  $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.  Logging --version etc. is OK.
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.59.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+  echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+  echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+  echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+  echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number, then exit
+  -q, --quiet      do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+  --file=FILE[:TEMPLATE]
+                  instantiate the configuration file FILE
+  --header=FILE[:TEMPLATE]
+                  instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.59,
+  with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "x$1" : 'x\([^=]*\)='`
+    ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  -*)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  *) # This is not an option, so the user has probably given explicit
+     # arguments.
+     ac_option=$1
+     ac_need_defaults=false;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --vers* | -V )
+    echo "$ac_cs_version"; exit 0 ;;
+  --he | --h)
+    # Conflict between --help and --header
+    { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    echo "$ac_cs_usage"; exit 0 ;;
+  --debug | --d* | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1" ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+  echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+  case "$ac_config_target" in
+  # Handling of arguments.
+  "MCONFIG" ) CONFIG_FILES="$CONFIG_FILES MCONFIG" ;;
+  "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+  "common/Makefile" ) CONFIG_FILES="$CONFIG_FILES common/Makefile" ;;
+  "compat/include/Makefile" ) CONFIG_FILES="$CONFIG_FILES compat/include/Makefile" ;;
+  "compat/lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES compat/lib/Makefile" ;;
+  "dump/Makefile" ) CONFIG_FILES="$CONFIG_FILES dump/Makefile" ;;
+  "restore/Makefile" ) CONFIG_FILES="$CONFIG_FILES restore/Makefile" ;;
+  "$RMTMAKEFILE" ) CONFIG_FILES="$CONFIG_FILES $RMTMAKEFILE" ;;
+  "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+  trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./confstat$$-$RANDOM
+  (umask 077 && mkdir $tmp)
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+  # Protect against being on the right side of a sed subst in config.status.
+  sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+   s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@LN_S@,$LN_S,;t t
+s,@CP@,$CP,;t t
+s,@MV@,$MV,;t t
+s,@RM@,$RM,;t t
+s,@AR@,$AR,;t t
+s,@ac_ct_AR@,$ac_ct_AR,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@PATCH@,$PATCH,;t t
+s,@ac_ct_PATCH@,$ac_ct_PATCH,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@DUMPDEBUG@,$DUMPDEBUG,;t t
+s,@RESTOREDEBUG@,$RESTOREDEBUG,;t t
+s,@STATIC@,$STATIC,;t t
+s,@RMTDIR@,$RMTDIR,;t t
+s,@ERMT@,$ERMT,;t t
+s,@CRYPTO@,$CRYPTO,;t t
+s,@OPTDEFS@,$OPTDEFS,;t t
+s,@READLINE@,$READLINE,;t t
+s,@LD@,$LD,;t t
+s,@CCOPTS@,$CCOPTS,;t t
+s,@LDOPTS@,$LDOPTS,;t t
+s,@BINOWNER@,$BINOWNER,;t t
+s,@BINGRP@,$BINGRP,;t t
+s,@BINMODE@,$BINMODE,;t t
+s,@MANOWNER@,$MANOWNER,;t t
+s,@MANGRP@,$MANGRP,;t t
+s,@MANMODE@,$MANMODE,;t t
+s,@DUMPDATESPATH@,$DUMPDATESPATH,;t t
+s,@BLKID@,$BLKID,;t t
+s,@ZLIB@,$ZLIB,;t t
+s,@BZLIB@,$BZLIB,;t t
+s,@top_builddir@,$top_builddir,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+/@MCONFIG@/r $MCONFIG
+s,@MCONFIG@,,;t t
+CEOF
+
+_ACEOF
+
+  cat >>$CONFIG_STATUS <<\_ACEOF
+  # Split the substitutions into bite-sized pieces for seds with
+  # small command number limits, like on Digital OSF/1 and HP-UX.
+  ac_max_sed_lines=48
+  ac_sed_frag=1 # Number of current file.
+  ac_beg=1 # First line for current file.
+  ac_end=$ac_max_sed_lines # Line after last line for current file.
+  ac_more_lines=:
+  ac_sed_cmds=
+  while $ac_more_lines; do
+    if test $ac_beg -gt 1; then
+      sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+    else
+      sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+    fi
+    if test ! -s $tmp/subs.frag; then
+      ac_more_lines=false
+    else
+      # The purpose of the label and of the branching condition is to
+      # speed up the sed processing (if there are no `@' at all, there
+      # is no need to browse any of the substitutions).
+      # These are the two extra sed commands mentioned above.
+      (echo ':t
+  /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+      if test -z "$ac_sed_cmds"; then
+       ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+      else
+       ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+      fi
+      ac_sed_frag=`expr $ac_sed_frag + 1`
+      ac_beg=$ac_end
+      ac_end=`expr $ac_end + $ac_max_sed_lines`
+    fi
+  done
+  if test -z "$ac_sed_cmds"; then
+    ac_sed_cmds=cat
+  fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case $ac_file in
+  - | *:- | *:-:* ) # input from stdin
+       cat >$tmp/stdin
+       ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+       ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+       ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  * )   ac_file_in=$ac_file.in ;;
+  esac
+
+  # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+  ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| \
+        .     : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+         /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+         /^X\(\/\/\)$/{ s//\1/; q; }
+         /^X\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+  { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| \
+        .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+         /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+         /^X\(\/\/\)$/{ s//\1/; q; }
+         /^X\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+  ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+  case "$ac_dir" in
+  .) ac_abs_builddir=`pwd`;;
+  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+  *) ac_abs_builddir=`pwd`/"$ac_dir";;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+  case ${ac_top_builddir}. in
+  .) ac_abs_top_builddir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+  case $ac_srcdir in
+  .) ac_abs_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+  case $ac_top_srcdir in
+  .) ac_abs_top_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+  esac;;
+esac
+
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+  esac
+
+  if test x"$ac_file" != x-; then
+    { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    rm -f "$ac_file"
+  fi
+  # Let's still pretend it is `configure' which instantiates (i.e., don't
+  # use $as_me), people would be surprised to read:
+  #    /* config.h.  Generated by config.status.  */
+  if test x"$ac_file" = x-; then
+    configure_input=
+  else
+    configure_input="$ac_file.  "
+  fi
+  configure_input=$configure_input"Generated from `echo $ac_file_in |
+                                    sed 's,.*/,,'` by configure."
+
+  # First look for the input files in the build tree, otherwise in the
+  # src tree.
+  ac_file_inputs=`IFS=:
+    for f in $ac_file_in; do
+      case $f in
+      -) echo $tmp/stdin ;;
+      [\\/$]*)
+        # Absolute (can't be DOS-style, as IFS=:)
+        test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+        echo "$f";;
+      *) # Relative
+        if test -f "$f"; then
+          # Build tree
+          echo "$f"
+        elif test -f "$srcdir/$f"; then
+          # Source tree
+          echo "$srcdir/$f"
+        else
+          # /dev/null tree
+          { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+        fi;;
+      esac
+    done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+  rm -f $tmp/stdin
+  if test x"$ac_file" != x-; then
+    mv $tmp/out $ac_file
+  else
+    cat $tmp/out
+    rm -f $tmp/out
+  fi
+
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([   ]*\)#\([        ]*define[       ][      ]*\)'
+ac_dB='[        ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([   ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case $ac_file in
+  - | *:- | *:-:* ) # input from stdin
+       cat >$tmp/stdin
+       ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+       ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+       ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  * )   ac_file_in=$ac_file.in ;;
+  esac
+
+  test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+  # First look for the input files in the build tree, otherwise in the
+  # src tree.
+  ac_file_inputs=`IFS=:
+    for f in $ac_file_in; do
+      case $f in
+      -) echo $tmp/stdin ;;
+      [\\/$]*)
+        # Absolute (can't be DOS-style, as IFS=:)
+        test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+        # Do quote $f, to prevent DOS paths from being IFS'd.
+        echo "$f";;
+      *) # Relative
+        if test -f "$f"; then
+          # Build tree
+          echo "$f"
+        elif test -f "$srcdir/$f"; then
+          # Source tree
+          echo "$srcdir/$f"
+        else
+          # /dev/null tree
+          { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+        fi;;
+      esac
+    done` || { (exit 1); exit 1; }
+  # Remove the trailing spaces.
+  sed 's/[      ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h.  The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status.  Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[    ]*#[    ]*define[       ][      ]*\([^  (][^    (]*\)\(([^)]*)\)[       ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[    ]*#[    ]*define[       ][      ]*\([^  ][^     ]*\)[   ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless.  Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[    ]*#[    ]*undef[        ][      ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo '  if grep "^[     ]*#[    ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo '  # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo '  :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+  # Write a limited-size here document to $tmp/defines.sed.
+  echo '  cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#define' lines.
+  echo '/^[     ]*#[    ]*define/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/defines.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo '  fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+  # Write a limited-size here document to $tmp/undefs.sed.
+  echo '  cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#undef'
+  echo '/^[     ]*#[    ]*undef/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+  rm -f conftest.undefs
+  mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+  # Let's still pretend it is `configure' which instantiates (i.e., don't
+  # use $as_me), people would be surprised to read:
+  #    /* config.h.  Generated by config.status.  */
+  if test x"$ac_file" = x-; then
+    echo "/* Generated by configure.  */" >$tmp/config.h
+  else
+    echo "/* $ac_file.  Generated by configure.  */" >$tmp/config.h
+  fi
+  cat $tmp/in >>$tmp/config.h
+  rm -f $tmp/in
+  if test x"$ac_file" != x-; then
+    if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| \
+        .     : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+         /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+         /^X\(\/\/\)$/{ s//\1/; q; }
+         /^X\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+      { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| \
+        .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+         /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+         /^X\(\/\/\)$/{ s//\1/; q; }
+         /^X\(\/\).*/{ s//\1/; q; }
+         s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+      rm -f $ac_file
+      mv $tmp/config.h $ac_file
+    fi
+  else
+    cat $tmp/config.h
+    rm -f $tmp/config.h
+  fi
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..bcafc46
--- /dev/null
@@ -0,0 +1,576 @@
+AC_INIT(dump/dump.h)
+AC_PREREQ(2.57)
+
+MCONFIG=./MCONFIG
+AC_SUBST_FILE(MCONFIG)
+
+AC_CONFIG_HEADER(config.h)
+
+dnl
+dnl Check for programs
+dnl
+AC_PROG_MAKE_SET
+AC_PROG_LN_S
+AC_PATH_PROG(CP, cp, cp)
+AC_PATH_PROG(MV, mv, mv)
+AC_PATH_PROG(RM, rm, rm)
+AC_CHECK_TOOL(AR, ar, ar)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+AC_CHECK_TOOL(PATCH, patch, :)
+AC_PROG_CC
+AC_PROG_INSTALL
+
+AC_CHECK_HEADERS([sys/types.h])
+
+CPPFLAGS="-D_BSD_SOURCE -D_USE_BSD_SIGNAL ${CPPFLAGS}"
+
+dnl
+dnl Handle --enable-debug
+dnl
+AC_ARG_ENABLE([debug],
+[  --enable-debug             include debugging code (default is NO)],
+if test "$enableval" = "no"
+then
+       DUMPDEBUG=""
+       RESTOREDEBUG=""
+       echo "Not including debugging code"
+else
+       DUMPDEBUG="-DFDEBUG -DTDEBUG -DWRITEDEBUG -DDIRDEBUG"
+       RESTOREDEBUG="-DDIRDEBUG"
+       echo "Including debugging code"
+fi,
+DUMPDEBUG=""
+RESTOREDEBUG=""
+echo "Not including debugging code by default"
+)
+AC_SUBST(DUMPDEBUG)
+AC_SUBST(RESTOREDEBUG)
+
+dnl
+dnl Handle --enable-static
+dnl
+AC_ARG_ENABLE([static],
+[  --enable-static            link dump and restore statically (default is NO)],
+if test "$enableval" = "no"
+then
+       STATIC=""
+       echo "Linking dump and restore dynamically"
+else
+       STATIC="-static"
+       echo "Linking dump and restore statically"
+fi
+,
+STATIC=""
+echo "Linking dump and restore dynamically by default"
+)
+AC_SUBST(STATIC)
+
+dnl
+dnl Handle --enable-staticz
+dnl
+AC_ARG_ENABLE([staticz],
+[  --enable-staticz           link libz and libbz2 statically (default is NO)],
+if test "$enableval" = "no"
+then
+       STATICZ="no"
+       echo "Linking libz and libbz2 dynamically"
+else
+       STATICZ="yes"
+       echo "Linking libz and libbz2 statically"
+fi
+,
+STATICZ="no"
+echo "Linking libz and libbz2 dynamically by default"
+)
+
+dnl
+dnl Handle --enable-rmt
+dnl
+AC_ARG_ENABLE([rmt],
+[  --enable-rmt               compile and install rmt (default is YES)],
+if test "$enableval" = "no"
+then
+       RMTDIR=""
+       RMTMAKEFILE=""
+       echo "Not compiling rmt"
+else
+       RMTDIR="rmt"
+       RMTMAKEFILE="rmt/Makefile"
+       echo "Compiling rmt"
+fi
+,
+RMTDIR="rmt"
+RMTMAKEFILE="rmt/Makefile"
+echo "Compiling rmt by default"
+)
+AC_SUBST(RMTDIR)
+
+dnl
+dnl Handle --enable-ermt
+dnl
+AC_ARG_ENABLE([ermt],
+[  --enable-ermt              compile ermt, an encrypting version of rmt (default is NO)],
+if test "$enableval" = "no"
+then
+       ERMT=""
+       CRYPTO=""
+       echo "Not compiling ermt"
+else
+       if test "$RMTDIR" = ""
+       then
+               AC_MSG_ERROR(ermt requires --enable-rmt)
+       fi
+       ERMT="ermt"
+       CRYPTO="-lcrypto"
+       echo "Compiling ermt"
+fi
+,
+ERMT=""
+CRYPTO=""
+echo "Not compiling ermt by default"
+)
+AC_SUBST(ERMT)
+AC_SUBST(CRYPTO)
+
+dnl
+dnl Handle --enable-kerberos
+dnl
+AC_ARG_ENABLE([kerberos],
+[  --enable-kerberos          compile kerberos extensions (default is NO)],
+if test "$enableval" = "yes"
+then
+       OPTDEFS="-DKERBEROS"
+       echo "Compiling kerberos extensions"
+else
+       OPTDEFS=""
+       echo "Not compiling kerberos extensions"
+fi
+,
+OPTDEFS=""
+echo "Not compiling kerberos extensions by default"
+)
+AC_SUBST(OPTDEFS)
+
+dnl
+dnl Handle --enable-readline
+dnl
+AC_ARG_ENABLE([readline],
+[  --enable-readline          enable readline support in restore (default is YES)],
+if test "$enableval" = "no"
+then
+       READLINE=""
+       echo "Not including readline support"
+else
+       READLINE="-lreadline -ltermcap"
+       AC_DEFINE([HAVE_READLINE],1,[Define if you want to include readline support.])
+       echo "Including readline support"
+fi
+,
+READLINE="-lreadline -ltermcap"
+AC_DEFINE([HAVE_READLINE],1,[Define if you want to include readline support.])
+echo "Including readline support by default"
+)
+AC_SUBST(READLINE)
+
+dnl
+dnl Handle --enable-oldsylefscript
+dnl
+AC_ARG_ENABLE([oldstylefscript],
+[  --enable-oldstylefscript   enable old style F script (no arguments) (default is NO)],
+if test "$enableval" = "yes"
+then
+       AC_DEFINE([OLD_STYLE_FSCRIPT],1,[Define this is you want old style F script (no arguments).])
+       echo "Using old style F script"
+else
+       echo "Using new style F script"
+fi
+,
+echo "Using new style F script by default"
+)
+
+dnl
+dnl Handle --enable-largefile
+dnl
+AC_ARG_ENABLE([largefile],
+[  --enable-largefile         enable Large File System support (default is YES)],
+if test "$enableval" = "yes"
+then
+       AC_DEFINE([USE_LFS],1,[Define this if you want Large File System support.])
+       echo "Enabling Large File System support"
+else
+       echo "Not enabling Large File System support"
+fi
+,
+AC_DEFINE([USE_LFS],1,[Define this if you want Large File System support.])
+echo "Enabling Large File System support by default"
+)
+
+dnl
+dnl Handle --enable-qfa
+dnl
+AC_ARG_ENABLE([qfa],
+[  --enable-qfa               enable Quick File Access support (default is YES)],
+if test "$enableval" = "yes"
+then
+       AC_DEFINE([USE_QFA],1,[Define this if you want Quick File Access support.])
+       echo "Enabling Quick File Access support"
+else
+       echo "Not enabling Quick File Access support"
+fi
+,
+AC_DEFINE([USE_QFA],1,[Define this if you want Quick File Access support.])
+echo "Enabling Quick File Access support by default"
+)
+
+dnl
+dnl Handle --enable-qfadebug
+dnl
+AC_ARG_ENABLE([qfadebug],
+[  --enable-qfadebug          include Quick File Access debugging code (default is NO)],
+if test "$enableval" = "yes"
+then
+       AC_DEFINE([DEBUG_QFA],1,[Define this if you want to include Quick File Access debugging code.])
+       echo "Including Quick File Access debugging code"
+else
+       echo "Not including Quick File Access debugging code"
+fi
+,
+echo "Not including Quick File Access debugging code by default"
+)
+
+dnl
+dnl Handle --enable-macosx
+dnl
+AC_ARG_ENABLE([macosx],
+[  --enable-macosx            include Mac OSX restore compatibility (default is NO)],
+if test "$enableval" = "yes"
+then
+       AC_DEFINE([DUMP_MACOSX],1,[Define this if you want to include Mac OSX restore compatibility.])
+       echo "Including Mac OSX restore compatibility code"
+else
+       echo "Not including Mac OSX restore compatibility code"
+fi
+,
+echo "Not including Mac OSX restore compatibility code by default"
+)
+
+
+dnl
+dnl set $(CC) from --with-cc=value
+dnl
+AC_ARG_WITH([cc],
+[  --with-cc=COMPILER         select compiler to use],
+AC_MSG_RESULT(CC=$withval)
+CC=$withval,
+if test -z "$CC" ; then CC=cc; fi
+[AC_MSG_RESULT(CC defaults to $CC)])dnl
+export CC
+AC_SUBST([CC])
+
+dnl
+dnl set $(LD) from --with-linker=value
+dnl
+AC_ARG_WITH([linker],
+[  --with-linker=LINKER       select linker to use],
+AC_MSG_RESULT(LD=$withval)
+LD=$withval,
+if test -z "$LD" ; then LD=$CC; fi
+[AC_MSG_RESULT(LD defaults to $LD)])dnl
+export LD
+AC_SUBST([LD])
+
+dnl
+dnl set $(CCOPTS) from --with-ccopts=value
+dnl
+AC_ARG_WITH([ccopts],
+[  --with-ccopts=CCOPTS       select compiler command line options],
+AC_MSG_RESULT(CCOPTS is $withval)
+CCOPTS=$withval
+CFLAGS="$CFLAGS $withval",
+CCOPTS=)dnl
+AC_SUBST(CCOPTS)
+
+dnl
+dnl set $(LDFLAGS) from --with-ldopts=value
+dnl
+AC_ARG_WITH([ldopts],
+[  --with-ldopts=LDOPTS       select linker command line options],
+AC_MSG_RESULT(LDFLAGS is $withval)
+LDOPTS=$withval
+LDFLAGS="$LDFLAGS $withval",
+LDOPTS=)dnl
+AC_SUBST(LDOPTS)
+
+dnl
+dnl set $(BINOWNER) from --with-binowner
+dnl
+AC_ARG_WITH([binowner],
+[  --with-binowner=USER       select owner for binaries],
+AC_MSG_RESULT(BINOWNER is $withval)
+BINOWNER=$withval,
+BINOWNER=root
+echo "BINOWNER defaults to $BINOWNER"
+)dnl
+AC_SUBST(BINOWNER)
+
+dnl
+dnl set $(BINGRP) from --with-bingrp
+dnl
+AC_ARG_WITH([bingrp],
+[  --with-bingrp=GROUP        select group for binaries],
+AC_MSG_RESULT(BINGRP is $withval)
+BINGRP=$withval,
+BINGRP=tty
+echo "BINGRP defaults to $BINGRP"
+)dnl
+AC_SUBST(BINGRP)
+
+dnl
+dnl set $(BINMODE) from --with-binmode
+dnl
+AC_ARG_WITH([binmode],
+[  --with-binmode=MODE        select mode for binaries],
+AC_MSG_RESULT(BINMODE is $withval)
+BINMODE=$withval,
+BINMODE=0755
+echo "BINMODE defaults to $BINMODE"
+)dnl
+AC_SUBST(BINMODE)
+
+dnl
+dnl set $(MANOWNER) from --with-manowner
+dnl
+AC_ARG_WITH([manowner],
+[  --with-manowner=USER       select owner for manual pages],
+AC_MSG_RESULT(MANOWNER is $withval)
+MANOWNER=$withval,
+MANOWNER=man
+echo "MANOWNER defaults to $MANOWNER"
+)dnl
+AC_SUBST(MANOWNER)
+
+dnl
+dnl set $(MANGRP) from --with-mangrp
+dnl
+AC_ARG_WITH([mangrp],
+[  --with-mangrp=GROUP        select group for manual pages],
+AC_MSG_RESULT(MANGRP is $withval)
+MANGRP=$withval,
+MANGRP=tty
+echo "MANGRP defaults to $MANGRP"
+)dnl
+AC_SUBST(MANGRP)
+
+dnl
+dnl set $(MANMODE) from --with-manmode
+dnl
+AC_ARG_WITH([manmode],
+[  --with-manmode=MODE        select mode for manual pages],
+AC_MSG_RESULT(MANMODE is $withval)
+MANMODE=$withval,
+MANMODE=0644
+echo "MANMODE defaults to $MANMODE"
+)dnl
+AC_SUBST(MANMODE)
+
+dnl
+dnl set $(DUMPDATESPATH) from --with-dumpdatespath
+dnl
+AC_ARG_WITH([dumpdatespath],
+[  --with-dumpdatespath=PATH  select path for dumpdates file],
+AC_MSG_RESULT(DUMPDATESPATH is $withval)
+DUMPDATESPATH=$withval,
+DUMPDATESPATH="${sysconfdir}/dumpdates"
+echo "DUMPDATESPATH defaults to $DUMPDATESPATH"
+)dnl
+AC_SUBST(DUMPDATESPATH)
+
+dnl
+dnl Check for Ext2fs headers and libraries
+dnl
+AC_CHECK_HEADER(ext2fs/ext2fs.h, [ext2fs_h=yes], [ext2fs_h=no], [-])
+AC_CHECK_LIB(ext2fs, ext2fs_open, [ext2fs_lib=yes], [ext2fs_lib=no], [-lcom_err])
+if test "$ext2fs_h" = no -o "$ext2fs_lib" = no; then
+       AC_MSG_ERROR(You need to install the Ext2fs libraries from the E2fsprogs distribution first - hint: make install-libs)
+fi
+
+dnl
+dnl Try to use ext2_fs.h header from libext2fs instead of from the kernel
+dnl
+AC_CHECK_HEADERS(ext2fs/ext2_fs.h, [], [], [-])
+
+dnl
+dnl Check for ext2_ino_t type
+dnl
+AC_MSG_CHECKING(for ext2_ino_t type in libext2fs headers)
+AC_TRY_COMPILE([#include <stdio.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>],
+[ext2_ino_t ino = 0;], 
+[AC_DEFINE([HAVE_EXT2_INO_T],1,[Define if we have the ext2_ino_t type (from e2fsprogs 1.20+).])
+ AC_MSG_RESULT(yes)],
+AC_MSG_RESULT(no))
+
+dnl
+dnl Check for s_journal_inum field in ext2_super_block struct
+dnl
+AC_MSG_CHECKING(for s_journal_inum field in ext2_super_block struct)
+AC_TRY_COMPILE([#include <stdio.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>],
+[struct ext2_super_block es; es.s_journal_inum = 0;],
+[AC_DEFINE([HAVE_EXT2_JOURNAL_INUM],1,[Define if we have the s_journal_inum field in struct ext2_super_block.])
+ AC_MSG_RESULT(yes)],
+AC_MSG_RESULT(no))
+
+dnl
+dnl Check for blkid headers libraries
+dnl
+AC_CHECK_HEADER(blkid/blkid.h, [blkid_h=yes], [blkid_h=no], [-])
+AC_CHECK_LIB(blkid, blkid_get_devname, [blkid_lib=yes], [blkid_lib=no], [-luuid])
+if test "$blkid_h" = yes -a "$blkid_lib" = yes; then
+       AC_DEFINE([HAVE_BLKID],1,[Define this if you have the blkid library.])
+       BLKID="-lblkid -luuid"
+fi
+AC_SUBST(BLKID)
+
+dnl
+dnl Check for termcap libraries
+dnl
+AC_CHECK_LIB(termcap, tgetent, [termcap_lib=yes], [termcap_lib=no])
+if test "$termcap_lib" = no; then
+       if test "$READLINE" = "-lreadline -ltermcap"; then
+               AC_MSG_ERROR(You need to install the GNU termcap library or configure without --enable-readline)
+       fi
+fi
+
+dnl
+dnl Check for readline headers and libraries
+dnl
+AC_CHECK_HEADER(readline/readline.h, [readline_h=yes], [readline_h=no], [-])
+AC_CHECK_LIB(readline, readline, [readline_lib=yes], [readline_lib=no], "-ltermcap")
+if test "$readline_h" = no -o "$readline_lib" = no; then
+       if test "$READLINE" = "-lreadline -ltermcap"; then
+               AC_MSG_ERROR(You need to install the GNU readline library or configure without --enable-readline)
+       fi
+fi
+
+dnl
+dnl Check for rl_completion_matches
+dnl
+AC_CHECK_LIB(readline, rl_completion_matches, [rlcm=yes], [rlcm=no], "-ltermcap")
+if test "$rlcm" = yes; then
+       AC_DEFINE([HAVE_READLINE_RLCM],1,[Define this if your readline libs have the rl_completion_matches library.])
+fi
+
+dnl
+dnl Check for rl_completion_append_character
+dnl
+AC_CHECK_LIB(readline, rl_completion_append_character, [rcac=yes], [rcac=no], "-ltermcap")
+if test "$rcac" = yes; then
+       AC_DEFINE([HAVE_READLINE_CAC],1,[Define this if your readline libs have the rl_completion_append_character variable.])
+fi
+
+dnl
+dnl Check for zlib headers and libraries
+dnl
+AC_CHECK_HEADER(zlib.h, [zlib_h=yes], [zlib_h=no], [-])
+AC_CHECK_LIB(z, compress2, [zlib_lib=yes], [zlib_lib=no])
+if test "$zlib_h" = yes -a "$zlib_lib" = yes; then
+       if test "$STATICZ" = yes; then
+               ZLIB="-Wl,-Bstatic -lz -Wl,-Bdynamic"
+       else
+               ZLIB="-lz"
+       fi
+       AC_DEFINE([HAVE_ZLIB],1,[Define this if you have zlib compression library.])
+else
+       ZLIB=""
+fi
+AC_SUBST(ZLIB)
+
+dnl
+dnl Check for bzlib headers and libraries
+dnl
+AC_CHECK_HEADER(bzlib.h, [bzlib_h=yes], [bzlib_h=no], [-])
+AC_CHECK_LIB(bz2, BZ2_bzBuffToBuffCompress, [bzlib_lib=yes], [bzlib_lib=no])
+if test "$bzlib_h" = yes -a "$bzlib_lib" = yes; then
+       if test "$STATICZ" = yes; then
+               BZLIB="-Wl,-Bstatic -lbz2 -Wl,-Bdynamic"
+       else
+               BZLIB="-lbz2"
+       fi
+       AC_DEFINE([HAVE_BZLIB],1,[Define this if you have bzlib compression library.])
+else
+       BZLIB=""
+fi
+AC_SUBST(BZLIB)
+
+dnl
+dnl Check for library functions
+dnl
+AC_CHECK_FUNCS(err errx verr verrx vwarn vwarnx warn warnx realpath lchown)
+AC_CHECK_FUNC(glob)
+
+dnl
+dnl Check for GLOB_ALTDIRFUNC
+dnl
+AC_MSG_CHECKING(for extended glob routines)
+if test "$ac_cv_func_glob" = "yes"; then
+       AC_EGREP_CPP(yes, 
+       [
+#      include <glob.h>
+#      ifdef GLOB_ALTDIRFUNC
+       yes
+#      endif
+       ], 
+       [
+       AC_DEFINE([HAVE_GLOB],1,[Define if you have the glob function.])
+       AC_MSG_RESULT(yes)
+       ],
+       [
+       AC_MSG_RESULT(no)
+       echo "Your system does not support extended glob, will use the internal routines"
+       ])
+fi
+
+dnl
+dnl Check for OpenSSL, for ermt
+dnl
+if test "$ERMT" != ""; then
+       AC_CHECK_HEADER(openssl/evp.h, [evp_h=yes], [evp_h=no])
+       AC_CHECK_LIB(crypto, EVP_CIPHER_CTX_set_padding, [crypto_lib=yes], [crypto_lib=no])
+       if test "$evp_h" = no -o "$crypto_lib" = no; then
+               AC_MSG_ERROR(You need to install the OpenSSL library (version 0.9.7a or later), or configure without --enable-ermt)
+       fi
+fi
+
+dnl
+dnl Check for types
+dnl
+AC_CHECK_TYPE(quad_t, int64_t)
+AC_CHECK_TYPE(u_quad_t, uint64_t)
+
+dnl
+dnl Compute top_buildir
+dnl
+top_builddir=`cd .; pwd`
+AC_SUBST(top_builddir)
+
+dnl
+dnl Create directories
+dnl
+test -d compat || mkdir compat
+test -d compat/lib || mkdir compat/lib
+
+dnl
+dnl Output files
+dnl
+AC_OUTPUT(MCONFIG Makefile common/Makefile compat/include/Makefile compat/lib/Makefile dump/Makefile restore/Makefile $RMTMAKEFILE)
diff --git a/depfix.sed b/depfix.sed
new file mode 100644 (file)
index 0000000..4ed209a
--- /dev/null
@@ -0,0 +1,34 @@
+# $Id: depfix.sed,v 1.2 1999/10/11 13:31:04 stelian Exp $
+#
+# Insert the header.....
+#
+1i\
+# +++ Dependency line eater +++\
+# \
+# Makefile dependencies follow.  This must be the last section in\
+# the Makefile.in file\
+#
+
+#
+# Remove line continuations....
+#
+#:FIRST
+#y/    / /
+#s/^ *//
+#/\\$/{
+#N
+#y/    / /
+#s/\\\n */ /
+#bFIRST
+#}
+#s/  */ /g
+
+s;/usr/include/[^ ]* *;;g
+s;/usr/lib/[^ ]* *;;g
+s;/mit/cygnus[^ ]* *;;g
+
+#
+# Now insert a trailing newline...
+#
+$a\
+
diff --git a/dump.lsm b/dump.lsm
new file mode 100644 (file)
index 0000000..73f53f7
--- /dev/null
+++ b/dump.lsm
@@ -0,0 +1,18 @@
+Begin3
+Title:          dump and restore for Ext2fs
+Version:        0.4b37
+Entered-date:   07JUL04
+Description:    Port of the 4.4BSD dump and restore backup suite
+Keywords:       backup, filesystem, Ext2fs
+Author:         University of California, Berkeley
+Maintained-by:  stelian@popies.net (Stelian Pop)
+Primary-site:   http://dump.sourceforge.net/
+                0kB dump-0.4b37.tar.gz
+                0 dump.lsm
+Original-site:  ftp.freebsd.org /pub/bsd-sources/4.4BSD-Lite2/sbin
+                dump/*
+                restore/*
+Platforms:      linux 2.0.x, linux 2.2.x, linux 2.4.x, linux 2.6.x
+               e2fsprogs 1.14 or better
+Copying-policy: BSD
+End
diff --git a/dump.spec b/dump.spec
new file mode 100644 (file)
index 0000000..ae0c08e
--- /dev/null
+++ b/dump.spec
@@ -0,0 +1,300 @@
+%define        _sbindir /sbin
+# XXX --enable-kerberos                needs krcmd
+%define        myoptions --with-binmode=6755 --with-manowner=root --with-mangrp=root --with-manmode=0644 --with-dumpdates="%{_sysconfdir}/dumpdates"
+
+Summary: Programs for backing up and restoring ext2/ext3 filesystems.
+Name: dump
+Version: 0.4b37
+Release: 1
+License: BSD
+URL: http://dump.sourceforge.net
+Group: Applications/Archiving
+Source: dump-%{version}.tar.gz
+BuildPrereq: e2fsprogs-devel >= 1.18
+BuildPrereq: libtermcap-devel, readline-devel
+BuildPrereq: zlib-devel, bzip2-devel
+Requires: rmt
+BuildRoot: %{_tmppath}/%{name}-root
+
+%description
+The dump package contains both dump and restore. Dump examines files
+in a filesystem, determines which ones need to be backed up, and
+copies those files to a specified disk, tape, or other storage medium.
+The restore command performs the inverse function of dump; it can
+restore a full backup of a filesystem. Subsequent incremental backups
+can then be layered on top of the full backup. Single files and
+directory subtrees may also be restored from full or partial backups.
+
+Install dump if you need a system for both backing up filesystems and
+restoring filesystems after backups.
+
+%package -n rmt
+Summary: Provides certain programs with access to remote tape devices.
+Group: Applications/Archiving
+
+%description -n rmt
+The rmt utility provides remote access to tape devices for programs
+like dump (a filesystem backup program), restore (a program for
+restoring files from a backup), and tar (an archiving program).
+
+%package -n dump-static
+Summary: Statically linked versions of dump and restore.
+Group: Applications/Archiving
+
+%description -n dump-static
+The dump package contains both dump and restore. Dump examines files in
+a filesystem, determines which ones need to be backed up, and copies
+those files to a specified disk, tape, or other storage medium. The
+restore command performs the inverse function of dump; it can restore a
+full backup of a filesystem. Subsequent incremental backups can then be
+layered on top of the full backup. Single files and directory subtrees
+may also be restored from full or partial backups.
+
+Install dump if you need a system for both backing up filesystems and
+restoring filesystems after backups.
+
+This package contains statically linked versions of dump and restore.
+
+%prep
+%setup -q
+
+%build
+%configure %{myoptions} --enable-static -disable-rmt
+
+%ifarch alpha
+RPM_OPT_FLAGS=""
+%endif
+make OPT="$RPM_OPT_FLAGS -Wall -Wpointer-arith -Wstrict-prototypes \
+                         -Wmissing-prototypes -Wno-char-subscripts"
+
+mv dump/dump dump/dump.static
+mv restore/restore restore/restore.static
+
+make distclean
+
+%configure %{myoptions}
+
+make OPT="$RPM_OPT_FLAGS -Wall -Wpointer-arith -Wstrict-prototypes \
+                         -Wmissing-prototypes -Wno-char-subscripts"
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}%{_sbindir}
+mkdir -p %{buildroot}%{_mandir}/man8
+
+%makeinstall SBINDIR=%{buildroot}%{_sbindir} MANDIR=%{buildroot}%{_mandir}/man8 BINOWNER=$(id -un) BINGRP=$(id -gn) MANOWNER=$(id -un) MANGRP=$(id -gn)
+mkdir -p $RPM_BUILD_ROOT/usr/sbin
+
+cp dump/dump.static %{buildroot}%{_sbindir}
+cp restore/restore.static %{buildroot}%{_sbindir}
+
+pushd $RPM_BUILD_ROOT
+  ln -sf dump .%{_sbindir}/rdump
+  ln -sf dump.static .%{_sbindir}/rdump.static
+  ln -sf restore .%{_sbindir}/rrestore
+  ln -sf restore.static .%{_sbindir}/rrestore.static
+  chmod ug-s .%{_sbindir}/rmt
+  mkdir -p .%{_sysconfdir}
+  > .%{_sysconfdir}/dumpdates
+  ln -sf ..%{_sbindir}/rmt .%{_sysconfdir}/rmt
+  # quick workaround :)
+  mv sbin/* usr/sbin/
+  mv usr/sbin/*static sbin/
+  mv usr/sbin/rmt sbin/
+  # somehow, rpm didn't strip these...
+  strip usr/sbin/* sbin/* || :  
+popd
+
+%clean
+rm -rf %{buildroot}
+
+%files
+%defattr(-,root,root)
+%doc CHANGES COPYRIGHT KNOWNBUGS MAINTAINERS README REPORTING-BUGS THANKS TODO
+%doc dump.lsm examples
+%attr(0664,root,disk)  %config(noreplace) %{_sysconfdir}/dumpdates
+%attr(0755,root,root)  /usr/sbin/dump
+/usr/sbin/rdump
+%attr(0755,root,root)  /usr/sbin/restore
+/usr/sbin/rrestore
+%{_mandir}/man8/dump.*
+%{_mandir}/man8/rdump.*
+%{_mandir}/man8/restore.*
+%{_mandir}/man8/rrestore.*
+
+%files -n rmt
+%defattr(-,root,root)
+%attr(0755,root,root)  %{_sbindir}/rmt
+%{_sysconfdir}/rmt
+%{_mandir}/man8/rmt.*
+
+%files -n dump-static
+%defattr(-,root,root)
+%attr(0755,root,root)  %{_sbindir}/dump.static
+%{_sbindir}/rdump.static
+%attr(0755,root,root)  %{_sbindir}/restore.static
+%{_sbindir}/rrestore.static
+
+%changelog
+* Wed Jul  7 2004 Stelian Pop <stelian@popies.net>
+- dump 0.4b37 released, first packaging.
+
+* Wed Apr 21 2004 Stelian Pop <stelian@popies.net>
+- dump 0.4b36 released, first packaging.
+
+* Sun Dec 21 2003 Stelian Pop <stelian@popies.net>
+- dump 0.4b35 released, first packaging.
+
+* Fri Apr 18 2003 Stelian Pop <stelian@popies.net>
+- dump 0.4b34 released, first packaging.
+
+* Mon Feb 10 2003 Stelian Pop <stelian@popies.net>
+- dump 0.4b33 released, first packaging.
+
+* Fri Nov 15 2002 Stelian Pop <stelian@popies.net>
+- dump 0.4b32 released, first packaging.
+
+* Tue Jul 30 2002 Stelian Pop <stelian@popies.net>
+- dump 0.4b31 released, first packaging.
+
+* Thu Jul 25 2002 Stelian Pop <stelian@popies.net>
+- dump 0.4b30 released, first packaging.
+
+* Sat Jun  8 2002 Stelian Pop <stelian@popies.net>
+- dump 0.4b29 released, first packaging.
+
+* Fri Apr 12 2002 Stelian Pop <stelian@popies.net>
+- dump 0.4b28 released, first packaging.
+
+* Fri Feb 15 2002 Stelian Pop <stelian@popies.net>
+- dump 0.4b27 released, first packaging.
+
+* Mon Jan  7 2002 Stelian Pop <stelian@popies.net>
+- dump 0.4b26 released, first packaging.
+
+* Sat Nov 17 2001 Stelian Pop <stelian@popies.net>
+- dump 0.4b25 released, first packaging.
+
+* Wed Sep 12 2001 Stelian Pop <stelian@popies.net>
+- dump 0.4b24 released, first packaging.
+
+* Fri Jul 20 2001 Stelian Pop <stelian@popies.net>
+- dump 0.4b23 released, first packaging.
+
+* Sat May 12 2001 Stelian Pop <stelian@popies.net>
+- dump 0.4b22 released, first packaging.
+
+* Sat Jan 30 2001 Stelian Pop <stelian@popies.net>
+- dump 0.4b21 released, first packaging.
+
+* Fri Nov 10 2000 Stelian Pop <stelian@popies.net>
+- dump 0.4b20 released, first packaging.
+
+* Sun Aug 20 2000 Stelian Pop <stelian@popies.net>
+- dump 0.4b19 released, first packaging.
+
+* Thu Jun 30 2000 Stelian Pop <stelian@popies.net>
+- dump 0.4b18 released, first packaging.
+
+* Thu Jun  1 2000 Stelian Pop <stelian@popies.net>
+- dump 0.4b17 released, first packaging.
+
+* Sat Mar 11 2000 Stelian Pop <stelian@popies.net>
+- dump 0.4b16 released, first packaging.
+
+* Thu Mar  2 2000 Stelian Pop <stelian@popies.net>
+- dump 0.4b15 released, first packaging.
+
+* Thu Feb 10 2000 Stelian Pop <stelian@popies.net>
+- dump 0.4b14 released, first packaging.
+
+* Fri Jan 21 2000 Stelian Pop <stelian@popies.net>
+- dump 0.4b13 released, first packaging.
+
+* Fri Jan 8 2000 Stelian Pop <stelian@popies.net>
+- dump 0.4b12 released, first packaging.
+
+* Sun Dec 5 1999 Stelian Pop <stelian@popies.net>
+- dump 0.4b11 released, first packaging.
+
+* Sun Nov 21 1999 Stelian Pop <stelian@popies.net>
+- dump 0.4b10 released, first packaging.
+
+* Thu Nov 11 1999 Stelian Pop <stelian@popies.net>
+- make static versions also for rescue purposes.
+
+* Wed Nov 5 1999 Stelian Pop <stelian@popies.net>
+- dump 0.4b9 released, first packaging.
+
+* Wed Nov 3 1999 Stelian Pop <stelian@popies.net>
+- dump 0.4b8 released, first packaging.
+
+* Thu Oct 8 1999 Stelian Pop <stelian@popies.net>
+- dump 0.4b7 released, first packaging.
+
+* Thu Sep 30 1999 Stelian Pop <stelian@popies.net>
+- dump 0.4b6 released, first packaging.
+
+* Fri Sep 10 1999 Jeff Johnson <jbj@redhat.com>
+- recompile with e2fsprogs = 1.15 (#4962).
+
+* Sat Jul 31 1999 Jeff Johnson <jbj@redhat.com>
+- workaround egcs bug (#4281) that caused dump problems (#2989).
+- use sigjmp_buf, not jmp_buf (#3260).
+- invoke /etc/rmt (instead of rmt) like other unices. (#3272).
+- use glibc21 err/glob rather than the internal compatibility routines.
+- wire $(OPT) throughout Makefile's.
+- fix many printf problems, mostly lint clean.
+- merge SuSE, Debian and many OpenBSD fixes.
+
+* Thu Mar 25 1999 Jeff Johnson <jbj@redhat.com>
+- remove setuid/setgid bits from /sbin/rmt (dump/restore are OK).
+
+* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com> 
+- auto rebuild in the new build environment (release 6)
+
+* Fri Mar 19 1999 Jeff Johnson <jbj@redhat.com>
+- strip binaries.
+
+* Thu Mar 18 1999 Jeff Johnson <jbj@redhat.com>
+- Fix dangling symlinks (#1551).
+
+* Wed Mar 17 1999 Michael Maher <mike@redhat.com>
+- Top O' the morning, build root's fixed for man pages.  
+
+* Fri Feb 19 1999 Preston Brown <pbrown@redhat.com>
+- upgraded to dump 0.4b4, massaged patches.
+
+* Tue Feb 02 1999 Ian A Cameron <I.A.Cameron@open.ac.uk>
+- added patch from Derrick J Brashear for traverse.c to stop bread errors
+
+* Wed Jan 20 1999 Jeff Johnson <jbj@redhat.com>
+- restore original 6755 root.tty to dump/restore, defattr did tty->root (#684).
+- mark /etc/dumpdates as noreplace.
+
+* Tue Jul 14 1998 Jeff Johnson <jbj@redhat.com>
+- add build root.
+
+* Tue May 05 1998 Prospector System <bugs@redhat.com>
+- translations modified for de, fr, tr
+
+* Thu Apr 30 1998 Cristian Gafton <gafton@redhat.com>
+- added a patch for resolving linux/types.h and sys/types.h conflicts
+
+* Wed Dec 31 1997 Erik Troan <ewt@redhat.com>
+- added prototype of llseek() so dump would work on large partitions
+
+* Thu Oct 30 1997 Donnie Barnes <djb@redhat.com>
+- made all symlinks relative instead of absolute
+
+* Thu Jul 10 1997 Erik Troan <ewt@redhat.com>
+- built against glibc
+
+* Thu Mar 06 1997 Michael K. Johnson <johnsonm@redhat.com>
+- Moved rmt to its own package.
+
+* Tue Feb 11 1997 Michael Fulbright <msf@redhat.com>
+- Added endian cleanups for SPARC
+
+* Fri Feb 07 1997 Michael K. Johnson <johnsonm@redhat.com> 
+- Made /etc/dumpdates writeable by group disk.
diff --git a/dump/Makefile.in b/dump/Makefile.in
new file mode 100644 (file)
index 0000000..f18c01e
--- /dev/null
@@ -0,0 +1,55 @@
+# $Id: Makefile.in,v 1.12 2004/07/05 15:02:36 stelian Exp $
+
+top_srcdir=    @top_srcdir@
+srcdir=                @srcdir@
+top_builddir=  ..
+
+@MCONFIG@
+
+INC=           -I$(top_srcdir)/dump
+ALL_CFLAGS=    @CPPFLAGS@ @CFLAGS@ @CCOPTS@ -pipe $(OPT) $(GINC) $(INC) $(DEFS) @DUMPDEBUG@
+ALL_LDFLAGS=   @LDFLAGS@ @LDOPTS@ @STATIC@
+LIBS=          $(GLIBS) @ZLIB@ @BZLIB@ @BLKID@
+DEPLIBS=       ../compat/lib/libcompat.a
+
+PROG=          dump
+RPROG=         rdump
+LINKS=         ${SBINDIR}/dump ${SBINDIR}/rdump
+SRCS=          itime.c main.c optr.c tape.c traverse.c unctime.c
+OBJS=          itime.o main.o optr.o tape.o traverse.o unctime.o \
+               ../common/dumprmt.o
+MAN8=          dump.8
+RMAN8=         rdump.8
+
+.c.o:
+       $(CC) -c $(ALL_CFLAGS) $< -o $@
+
+all::          $(PROG) $(MAN8)
+
+$(PROG):       $(OBJS) $(DEPLIBS)
+       $(LD) $(ALL_LDFLAGS) -o $(PROG) $(OBJS) $(LIBS)
+
+$(MAN8):       dump.8.in
+       sed -e "s|__DUMPDATES__|$(DUMPDATESPATH)|g" \
+           -e "s|__DATE__|$(DATE)|g" \
+           -e "s|__VERSION__|$(VERSION)|g" $< > $@
+
+install::      all
+       $(INSTALL) -d $(SBINDIR) $(MANDIR)
+       $(INSTALLBIN) $(PROG) $(SBINDIR)
+       $(INSTALLMAN) $(MAN8) $(MANDIR)
+       cd $(SBINDIR) && $(RM) -f $(RPROG) && $(LN_S) $(PROG) $(RPROG)
+       cd $(MANDIR) && $(RM) -f $(RMAN8) && $(LN_S) $(MAN8) $(RMAN8)
+
+clean::
+       $(RM) -f $(PROG) $(MAN8) \#* *.s *.o *.a *~ core
+
+distclean::    clean
+       $(RM) -f Makefile Makefile.old .depend
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+
diff --git a/dump/dump.8.in b/dump/dump.8.in
new file mode 100644 (file)
index 0000000..487302d
--- /dev/null
@@ -0,0 +1,660 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\"     Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: dump.8.in,v 1.56 2004/04/21 08:55:48 stelian Exp $
+.\"
+.TH DUMP 8 "version __VERSION__ of __DATE__" BSD "System management commands"
+.SH NAME
+dump \- ext2/3 filesystem backup
+.SH SYNOPSIS
+.B dump 
+[\fB\-\fIlevel#\fR]
+[\fB\-ackMnqSuv]
+[\fB\-A \fIfile\fR]
+[\fB\-B \fIrecords\fR]
+[\fB\-b \fIblocksize\fR]
+[\fB\-d \fIdensity\fR]
+[\fB\-D \fIfile\fR]
+[\fB\-e \fIinode numbers\fR]
+[\fB\-E \fIfile\fR]
+[\fB\-f \fIfile\fR]
+[\fB\-F \fIscript\fR]
+[\fB\-h \fIlevel\fR]
+[\fB\-I \fInr errors\fR]
+[\fB\-j\fIcompression level\fR]
+[\fB\-L \fIlabel\fR]
+[\fB\-Q \fIfile\fR]
+[\fB\-s \fIfeet\fR]
+[\fB\-T \fIdate\fR]
+[\fB\-y\fR]
+[\fB\-z\fIcompression level\fR]
+.I files-to-dump
+.PP
+.B dump 
+[\fB\-W \fR| \fB\-w\fR]
+.PP
+(The 4.3BSD option syntax is implemented for backward compatibility but is not
+documented here.)
+.SH DESCRIPTION
+.B Dump
+examines files on an ext2/3 filesystem and determines which files need to be
+backed up. These files are copied to the given disk, tape or other storage
+medium for safe keeping (see the
+.B \-f 
+option below for doing remote backups). A dump that is larger than the output 
+medium is broken into multiple volumes. On most media the size is determined by
+writing until an end-of-media indication is returned.
+.PP
+On media that cannot reliably return an end-of-media indication (such as some
+cartridge tape drives), each volume is of a fixed size; the actual size is 
+determined by specifying cartridge media, or via the tape size, density and/or
+block count options below. By default, the same output file name is used for
+each volume after prompting the operator to change media.
+.PP
+.I files-to-dump
+is either a mountpoint of a filesystem or a list of files and directories to be
+backed up as a subset of a filesystem. In the former case, either the path to a
+mounted filesystem or the device of an unmounted filesystem can be used. In the
+latter case, certain restrictions are placed on the backup:
+.B \-u
+is not allowed, the only dump level that is supported is
+.B 0 
+and all the files and directories must reside on the same filesystem.
+.SH OPTIONS
+The following options are supported by
+.B dump:
+.TP
+.BI \-level#
+The dump level (any integer). A level 0, full backup, guarantees the
+entire file system is copied (but see also the
+.B \-h
+option below). A level number above 0, incremental backup, tells
+.B dump
+to
+copy all files new or modified since the last dump of a lower level. The 
+default level is 9. Historically only levels 0 to 9 were usable in
+dump, this version is able to understand any integer as a dump level.
+.TP
+.BI \-a 
+\*(lqauto-size\*(rq. Bypass all tape length calculations, and write until an 
+end-of-media indication is returned.  This works best for most modern tape
+drives, and is the default. Use of this option is particularly recommended when
+appending to an existing tape, or using a tape drive with hardware compression 
+(where you can never be sure about the compression ratio).
+.TP
+.BI \-A " archive_file"
+Archive a dump table-of-contents in the specified
+.I archive_file
+to be used by 
+.BR restore (8)
+to determine whether a file is in the dump file that is being restored.
+.TP
+.BI \-b " blocksize"
+The number of kilobytes per dump record. The default blocksize is 10,
+unless the
+.B \-d
+option has been used to specify a tape density of 6250BPI or more,
+in which case the default blocksize is 32. Th maximal value is 1024.
+Note however that, since the IO system slices all requests into chunks
+of 
+.B MAXBSIZE
+(which can be as low as 64kB), you can experience problems with
+.BR dump (8)
+and
+.BR restore (8)
+when using a higher value, depending on your kernel and/or libC versions.
+.TP
+.BI \-B " records"
+The number of 1 kB blocks per volume. Not normally required, as
+.B dump
+can detect end-of-media. When the specified size is reached,
+.B dump
+waits for you to change the volume.  This option overrides the calculation of 
+tape size based on length and density. If compression is on this limits the 
+size of the compressed output per volume.  Multiple values may be given
+as a single argument separated by commas.  Each value will be used for one
+dump volume in the order listed; if
+.B dump
+creates more volumes than the
+number of values given, the last value will be used for the remaining
+volumes. This is useful for filling up already partially filled media
+(and then continuing with full size volumes on empty media) or mixing media
+of different sizes.
+.TP
+.BI \-c
+Change the defaults for use with a cartridge tape drive, with a density of 8000
+bpi, and a length of 1700 feet. Specifying a cartridge drive overrides the
+end-of-media detection.
+.TP
+.BI \-d " density"
+Set tape density to
+.IR density .
+The default is 1600BPI. Specifying a tape density overrides the end-of-media
+detection.
+.TP
+.BI \-D " file"
+Set the path name of the file storing the information about the previous 
+full and incremental dumps. The default location is
+.IR __DUMPDATES__ .
+.TP
+.BI \-e " inodes"
+Exclude 
+.I inodes
+from the dump. The
+.I inodes
+parameter is a comma separated list of inode numbers (you can use
+.BR stat (1)
+to find the inode number for a file or directory).
+.TP
+.BI \-E " file"
+Read list of inodes to be excluded from the dump from the text file
+.IR file .
+The file 
+.I file
+should be an ordinary file containing inode numbers separated by newlines.
+.TP
+.BI \-f " file"
+Write the backup to
+.IR file ;
+.I file
+may be a special device file like
+.I /dev/st0
+(a tape drive),
+.I /dev/rsd1c
+(a floppy disk drive), an ordinary file, or
+.I \-
+(the standard output). Multiple file names may be given as a single argument
+separated by commas. Each file will be used for one dump volume in the order
+listed; if the dump requires more volumes than the number of names given,
+the last file name will used for all remaining volumes after prompting for
+media changes. If the name of the file is of the form
+.I host:file
+or
+.I user@host:file
+.B dump
+writes to the named file on the remote host (which should already 
+exist, dump doesn't create a new remote file) using
+.BR rmt (8).
+The default path name of the remote
+.BR rmt (8)
+program is
+.IR /etc/rmt ;
+this can be overridden by the environment variable
+.BR RMT .
+.TP
+.BI \-F " script"
+Run script at the end of each tape (except for the last one). 
+The device name and the current volume number are passed on the
+command line. The script must return 0 if 
+.B dump
+should continue without asking the user to change the tape, 1 if 
+.B dump
+should continue but ask the user to change the tape. Any other exit code will 
+cause
+.B dump
+to abort. For security reasons,
+.B dump
+reverts back to the real user ID and the real group ID before running the
+script.
+.TP
+.BI \-h " level"
+Honor the user
+.B nodump
+flag
+.B UF_NODUMP
+only for dumps at or above the given
+.IR level .
+The default honor level is 1, so that incremental backups omit such files but
+full backups retain them.
+.TP
+.BI \-I " nr errors"
+By default,
+.B dump
+will ignore the first 32 read errors on the file system before asking for 
+operator intervention. You can change this using this flag to any value. This 
+is useful when running
+.B dump
+on an active filesystem where read errors simply indicate an inconsistency 
+between the mapping and dumping passes.
+.IP
+A value of 0 means that all read errors will be ignored.
+.TP
+.BI \-j "compression level"
+Compress every block to be written on the tape using bzlib library. This option
+will work only when dumping to a file or pipe or, when dumping to a tape drive,
+if the tape drive is capable of writing variable length blocks. You will need
+at least the 0.4b24 version of 
+.B restore
+in order to extract compressed tapes. Tapes written using compression will not
+be compatible with the BSD tape format. The (optional) parameter specifies the 
+compression level bzlib will use. The default compression level is 2. If the
+optional parameter is specified, there should be no white space between the 
+option letter and the parameter.
+.TP
+.BI \-k
+Use Kerberos authentication to talk to remote tape servers. (Only available if
+this option was enabled when
+.B dump
+was compiled.)
+.TP
+.BI \-L " label"
+The user-supplied text string
+.I label
+is placed into the dump header, where tools like
+.BR restore (8)
+and
+.BR file (8)
+can access it. Note that this label is limited to be at most 
+.B LBLSIZE
+(currently 16) characters, which must include the terminating \e0.
+.TP
+.BI \-m
+If this flag is specified,
+.B dump
+will optimise the output for inodes having been changed but not modified since 
+the last dump ('changed' and 'modified' have the meaning defined in
+.BR stat (2)
+). For those inodes,
+.B dump
+will save only the metadata, instead of saving the entire inode contents. 
+Inodes which are either directories or have been modified since the last dump 
+are saved in a regular way. Uses of this flag must be consistent, meaning that
+either every dump in an incremental dump set have the flag, or no one has it.
+.IP
+Tapes written using such 'metadata only' inodes will not be compatible with the
+BSD tape format or older versions of
+.B restore.
+.TP
+.BI \-M
+Enable the multi-volume feature. The name specified with 
+.B f 
+is treated as a prefix and 
+.B dump
+writes in sequence to
+.I <prefix>001, <prefix>002 
+etc. This can be useful when dumping to files on an ext2 partition, in order to
+bypass the 2GB file size limitation.
+.TP
+.BI \-n
+Whenever
+.B dump
+requires operator attention, notify all operators in the group
+.B operator
+by means similar to a
+.BR wall (1).
+.TP
+.BI \-q
+Make
+.B dump
+abort immediately whenever operator attention is required, without prompting in
+case of write errors, tape changes etc.
+.TP
+.BI \-Q " file"
+Enable the Quick File Access support. Tape positions for each inode are stored 
+into the file
+.I file
+which is used by 
+.B restore
+(if called with parameter 
+.B \-Q
+and the filename) to directly position the tape at the file 
+.B restore 
+is currently working on. This saves hours when restoring single files from
+large backups, saves the tapes and the drive's head.
+.IP
+It is recommended to set up the st driver to return logical tape positions 
+rather than physical before calling 
+.B dump/restore 
+with parameter 
+.BR \-Q .
+Since not all tape devices support physical tape positions those tape devices 
+return an error during 
+.B dump/restore
+when the st driver is set to the default physical setting.  Please see the 
+.BR st (4)
+man page, option 
+.B MTSETDRVBUFFER
+, or the 
+.BR mt (1)
+man page, on how to set the driver to return logical tape positions.
+.IP
+Before calling
+.B restore
+with parameter
+.BR \-Q ,
+always make sure the st driver is set to return the same type of tape position
+used during the call to 
+.BR dump .
+Otherwise 
+.B restore
+may be confused.
+.IP
+This option can be used when dumping to local tapes (see above) or to local 
+files.
+.TP
+.BI \-s " feet"
+Attempt to calculate the amount of tape needed at a particular density. If this
+amount is exceeded,
+.B dump
+prompts for a new tape. It is recommended to be a bit conservative on this 
+option. The default tape length is 2300 feet. Specifying the tape size 
+overrides end-of-media detection.
+.TP
+.BI \-S
+Size estimate. Determine the amount of space that is needed to perform the dump
+without actually doing it, and display the estimated number of bytes it will
+take. This is useful with incremental dumps to determine how many volumes of
+media will be needed.
+.TP
+.BI \-T " date"
+Use the specified date as the starting time for the dump instead of the time 
+determined from looking in
+.I __DUMPDATES__ .
+The format of
+.I date
+is the same as that of
+.BR ctime (3)
+followed by an rfc822 timezone specification: either a plus or minus sign
+followed by two digits for the number of hours and two digits for the minutes.
+For example, -0800 for eight hours west of Greenwich or +0230 for two hours
+and a half east of Greenwich. This timezone offset takes into account
+daylight savings time (if applicable to the timezone): UTC offsets
+when daylight savings time is in effect will be different than offsets
+when daylight savings time is not in effect. For backward
+compatibility, if no timezone is specified, a local time is assumed.
+This option is useful for automated dump scripts that wish to dump over a 
+specific period of time. The
+.B \-T
+option is mutually exclusive from the
+.B \-u
+option.
+.TP
+.BI \-u
+Update the file
+.I __DUMPDATES__
+after a successful dump. The format of
+.I __DUMPDATES__
+is readable by people, consisting of one free format record per line:
+filesystem name, increment level and
+.BR ctime (3)
+format dump date followed by a rfc822 timezone specification (see the
+.B \-u
+option for details). If no timezone offset is specified, times are interpreted 
+as local. Whenever the file is written, all dates in the file are converted 
+to the local time zone, without changing the UTC times. There
+may be only one entry per filesystem at each level. The file
+.I __DUMPDATES__
+may be edited to change any of the fields, if necessary.
+.TP
+.BI \-v
+The
+.B \-v
+(verbose) makes
+.B dump
+to print extra information which could be helpful in debug sessions.
+.TP
+.BI \-W
+.B Dump
+tells the operator what file systems need to be dumped. This information is
+gleaned from the files
+.I __DUMPDATES__
+and
+.IR /etc/fstab .
+The
+.B \-W
+option causes
+.B dump
+to print out, for all file systems in
+.I __DUMPDATES__ ,
+and regognized file systems in
+.I /etc/mtab
+and
+.IR /etc/fstab .
+the most recent dump date and level, and highlights those that should be 
+dumped. If the
+.B \-W
+option is set, all other options are ignored, and
+.B dump
+exits immediately.
+.TP 
+.BI \-w
+Is like
+.BR \-W ,
+but prints only recognized filesystems in
+.I /etc/mtab
+and
+.I /etc/fstab
+which need to be dumped.
+.TP
+.BI \-y
+Compress every block to be written to the tape using the lzo library.
+This doesn't compress as well as the zlib library but it's much faster.
+This option will work only when dumping to a file or pipe or, when dumping to
+a tape drive, if the tape drive is capable of writing variable length blocks.
+You will need at least the 0.4b34 version of
+.B restore
+in order to extract compressed tapes. Tapes written using compression will not
+be compatible with the BSD tape format.
+.TP
+.BI \-z "compression level"
+Compress every block to be written on the tape using zlib library. This option
+will work only when dumping to a file or pipe or, when dumping to a tape drive,
+if the tape drive is capable of writing variable length blocks. You will need 
+at least the 0.4b22 version of
+.B restore
+in order to extract compressed tapes. Tapes written using compression will not
+be compatible with the BSD tape format. The (optional) parameter specifies the
+compression level zlib will use. The default compression level is 2. If the
+optional parameter is specified, there should be no white space between the 
+option letter and the parameter.
+.PP
+.B Dump
+requires operator intervention on these conditions: end of tape, end of dump,
+tape write error, tape open error or disk read error (if there is more than a 
+threshold of nr errors). In addition to alerting all operators implied by the
+.B \-n
+key,
+.B dump
+interacts with the operator on dump's control terminal at times when
+.B dump
+can no longer proceed, or if something is grossly wrong. All questions
+.B dump
+poses
+.I must
+be answered by typing \*(lqyes\*(rq or \*(lqno\*(rq, appropriately.
+.PP
+Since making a dump involves a lot of time and effort for full dumps,
+.B dump
+checkpoints itself at the start of each tape volume. If writing that volume
+fails for some reason,
+.B dump
+will, with operator permission, restart itself from the checkpoint after the
+old tape has been rewound and removed, and a new tape has been mounted.
+.PP
+.B Dump
+tells the operator what is going on at periodic intervals, including usually 
+low estimates of the number of blocks to write, the number of tapes it will
+take, the time to completion, and the time to the tape change. The output is
+verbose, so that others know that the terminal controlling
+.B dump
+is busy, and will be for some time.
+.PP
+In the event of a catastrophic disk event, the time required to restore all the
+necessary backup tapes or files to disk can be kept to a minimum by staggering 
+the incremental dumps. An efficient method of staggering incremental dumps to
+minimize the number of tapes follows:
+.IP \(em
+Always start with a level 0 backup, for example:
+.RS 14
+.B /sbin/dump -0u -f /dev/st0 /usr/src
+.RE
+.IP
+This should be done at set intervals, say once a month or once every two months,
+and on a set of fresh tapes that is saved forever.
+.IP \(em
+After a level 0, dumps of active file systems are taken on a daily basis, using
+a modified Tower of Hanoi algorithm, with this sequence of dump levels:
+.RS 14
+.B 3 2 5 4 7 6 9 8 9 9 ...
+.RE
+.IP
+For the daily dumps, it should be possible to use a fixed number of tapes for
+each day, used on a weekly basis. Each week, a level 1 dump is taken, and the
+daily Hanoi sequence repeats beginning with 3. For weekly dumps, another fixed 
+set of tapes per dumped file system is used, also on a cyclical basis.
+.PP
+After several months or so, the daily and weekly tapes should get rotated out
+of the dump cycle and fresh tapes brought in.
+.SH ENVIRONMENT
+.TP 
+.B TAPE
+If no 
+.B \-f 
+option was specified,
+.B dump
+will use the device specified via
+.B TAPE
+as the dump device.
+.B TAPE
+may be of the form
+.IR tapename ,
+.IR host:tapename ,
+or
+.IR user@host:tapename .
+.TP
+.B RMT
+The environment variable
+.B RMT
+will be used to determine the pathname of the remote
+.BR rmt (8)
+program.
+.TP
+.B RSH
+.B Dump
+uses the contents of this variable to determine the name of the remote shell
+command to use when doing remote backups (rsh, ssh etc.). If this variable is
+not set, 
+.BR rcmd (3)
+will be used, but only root will be able to do remote backups.
+.SH FILES
+.TP
+.I /dev/st0
+default tape unit to dump to
+.TP
+.I __DUMPDATES__
+dump date records
+.TP
+.I /etc/fstab
+dump table: file systems and frequency
+.TP
+.I /etc/mtab
+dump table: mounted file systems
+.TP
+.I /etc/group
+to find group
+.I operator
+.SH SEE ALSO
+.BR fstab (5),
+.BR restore (8),
+.BR rmt (8)
+.SH DIAGNOSTICS
+Many, and verbose.
+.SH COMPATIBILITY
+The format of the
+.I __DUMPDATES__
+file has changed in release 0.4b34, however, the file will be read
+correctly with either pre-0.4b34 or 0.4b34 and later versions of
+.B dump
+provided that the machine on which
+.B dump
+is run did not change timezones (which should be a fairly rare occurence).
+.SH EXIT STATUS
+.B Dump
+exits with zero status on success. Startup errors are indicated with an exit
+code of 1; abnormal termination is indicated with an exit code of 3.
+.SH BUGS
+It might be considered a bug that this version of dump can only handle ext2/3
+filesystems.  Specifically, it does not work with FAT filesystems.
+.PP
+Fewer than 32 read errors (change this with 
+.BR \-I )
+on the filesystem are ignored. If noticing read errors is important, the output
+from dump can be parsed to look for lines that contain the text 'read error'.
+.PP
+When a read error occurs,
+.B dump
+prints out the corresponding physical disk block and sector number and the
+ext2/3 logical block number. It doesn't print out the corresponing file name or
+even the inode number. The user has to use 
+.BR debugfs (8),
+commands
+.B ncheck
+and
+.B icheck
+to translate the
+.B ext2blk
+number printed out by 
+.B dump
+into an inode number, then into a file name.
+.PP
+Each reel requires a new process, so parent processes for reels already written
+just hang around until the entire tape is written.
+.PP
+The estimated number of tapes is not correct if compression is on.
+.PP
+It would be nice if
+.B dump
+knew about the dump sequence, kept track of the tapes scribbled on, told the
+operator which tape to mount when, and provided more assistance for the 
+operator running
+.BR restore .
+.PP
+.B Dump
+cannot do remote backups without being run as root, due to its security history.
+Presently, it works if you set it setuid (like it used to be), but this might
+constitute a security risk. Note that you can set 
+.B RSH
+to use a remote shell program instead.
+.SH AUTHOR
+The 
+.B dump/restore
+backup suite was ported to Linux's Second Extended File System by Remy Card 
+<card@Linux.EU.Org>. He maintained the initial versions of 
+.B dump
+(up and including 0.4b4, released in january 1997).
+.PP
+Starting with 0.4b5, the new maintainer is Stelian Pop <stelian@popies.net>.
+.SH AVAILABILITY
+The
+.B dump/restore
+backup suite is available from <http://dump.sourceforge.net>
+.SH HISTORY
+A
+.B dump
+command appeared in
+.B Version 6 AT&T UNIX.
diff --git a/dump/dump.h b/dump/dump.h
new file mode 100644 (file)
index 0000000..fafd4c3
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: dump.h,v 1.49 2004/07/01 09:14:49 stelian Exp $
+ */
+
+/*-
+ * Copyright (c) 1980, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <protocols/dumprestore.h>
+#include <compatlfs.h>
+
+#define MAXINOPB       (MAXBSIZE / sizeof(struct dinode))
+#define MAXNINDIR      (MAXBSIZE / sizeof(blk_t))
+#define NUM_STR_SIZE   32      /* a generic number buffer size */
+
+/*
+ * Dump maps used to describe what is to be dumped.
+ */
+extern int     mapsize;        /* size of the state maps */
+extern char    *usedinomap;    /* map of allocated inodes */
+extern char    *dumpdirmap;    /* map of directories to be dumped */
+extern char    *dumpinomap;    /* map of files to be dumped */
+extern char    *metainomap;    /* which of the inodes in dumpinomap
+                                  will get only their metadata dumped */
+/*
+ * Map manipulation macros.
+ */
+#define        SETINO(ino, map) \
+       map[(u_int)((ino) - 1) / NBBY] |=  1 << ((u_int)((ino) - 1) % NBBY)
+#define        CLRINO(ino, map) \
+       map[(u_int)((ino) - 1) / NBBY] &=  ~(1 << ((u_int)((ino) - 1) % NBBY))
+#define        TSTINO(ino, map) \
+       (map[(u_int)((ino) - 1) / NBBY] &  (1 << ((u_int)((ino) - 1) % NBBY)))
+
+/*
+ *     All calculations done in 0.1" units!
+ */
+extern char    *host;          /* name of the remote host */
+extern const char *disk;       /* name of the disk file */
+extern char    tape[MAXPATHLEN];/* name of the tape file */
+extern char    *tapeprefix;    /* prefix of the tape file */
+extern char    *dumpdates;     /* name of the file containing dump date information*/
+extern char    lastlevel[NUM_STR_SIZE];/* dump level of previous dump */
+extern char    level[NUM_STR_SIZE];/* dump level of this dump */
+extern int     Afile;          /* archive file descriptor */
+extern int      AfileActive;    /* Afile flag */
+extern int     zipflag;        /* which compression method */
+extern int     uflag;          /* update flag */
+extern int     mflag;          /* dump metadata only if possible flag */
+extern int     Mflag;          /* multi-volume flag */
+extern int     qflag;          /* quit on errors flag */
+extern int     vflag;          /* verbose flag */
+extern int      breademax;      /* maximum number of bread errors before we quit */
+extern char    *eot_script;    /* end of volume script fiag */
+extern int     diskfd;         /* disk file descriptor */
+extern int     tapefd;         /* tape file descriptor */
+extern int     pipeout;        /* true => output to standard output */
+extern int     fifoout;        /* true => output to fifo */
+extern dump_ino_t curino;      /* current inumber; used globally */
+extern int     newtape;        /* new tape flag */
+extern int     density;        /* density in 0.1" units */
+extern long    tapesize;       /* estimated tape size, blocks */
+extern long    tsize;          /* tape size in 0.1" units */
+extern long    asize;          /* number of 0.1" units written on current tape */
+extern int     etapes;         /* estimated number of tapes */
+extern int     nonodump;       /* if set, do not honor UF_NODUMP user flags */
+extern int     unlimited;      /* if set, write to end of medium */
+extern int     compressed;     /* if set, dump is to be compressed */
+extern long long bytes_written;/* total bytes written to tape */
+extern long    uncomprblks;    /* uncompressed blocks written to tape */
+extern int     notify;         /* notify operator flag */
+extern int     blockswritten;  /* number of blocks written on current tape */
+extern int     tapeno;         /* current tape number */
+extern time_t  tstart_writing; /* when started writing the first tape block */
+extern time_t  tend_writing;   /* after writing the last tape block */
+#ifdef __linux__
+extern ext2_filsys fs;
+#else
+extern struct  fs *sblock;     /* the file system super block */
+extern char    sblock_buf[MAXBSIZE];
+#endif
+extern long    xferrate;       /* averaged transfer rate of all volumes */
+extern long    dev_bsize;      /* block size of underlying disk device */
+extern int     dev_bshift;     /* log2(dev_bsize) */
+extern int     tp_bshift;      /* log2(TP_BSIZE) */
+extern dump_ino_t volinfo[];   /* which inode on which volume archive info */
+
+#ifdef USE_QFA
+#define        QFA_MAGIC       "495115637697"
+#define QFA_VERSION    "1.0"
+extern int     gTapeposfd;
+extern char    *gTapeposfile;
+extern char    gTps[255];
+extern int32_t gThisDumpDate;
+#endif /* USE_QFA */
+
+#ifndef __P
+#include <sys/cdefs.h>
+#endif
+
+/* operator interface functions */
+void   broadcast __P((const char *message));
+time_t do_stats __P((void));
+void   lastdump __P((char arg));
+void   msg __P((const char *fmt, ...));
+void   msgtail __P((const char *fmt, ...));
+int    query __P((const char *question));
+void   quit __P((const char *fmt, ...));
+void   set_operators __P((void));
+#if defined(SIGINFO)
+void   statussig __P((int signo));
+#endif
+void   timeest __P((void));
+time_t unctime __P((const char *str));
+
+/* mapping rouintes */
+struct dinode;
+long   blockest __P((struct dinode const *dp));
+int    mapfiles __P((dump_ino_t maxino, long *tapesize));
+#ifdef __linux__
+int    mapfilesfromdir __P((dump_ino_t maxino, long *tapesize, char *directory));
+int    maponefile __P((dump_ino_t maxino, long *tapesize, char *directory));
+#endif
+int    mapdirs __P((dump_ino_t maxino, long *tapesize));
+
+/* file dumping routines */
+void   blksout __P((blk_t *blkp, int frags, dump_ino_t ino));
+void   bread __P((ext2_loff_t blkno, char *buf, int size));
+void   dumpino __P((struct dinode *dp, dump_ino_t ino, int metaonly));
+#ifdef __linux__
+void   dumpdirino __P((struct dinode *dp, dump_ino_t ino));
+#endif
+void   dumpmap __P((char *map, int type, dump_ino_t ino));
+void   writeheader __P((dump_ino_t ino));
+void   mkchecksum __P((union u_spcl *tmpspcl));
+
+/* tape writing routines */
+int    alloctape __P((void));
+void   close_rewind __P((void));
+void   dumpblock __P((blk_t blkno, int size));
+void   startnewtape __P((int top));
+time_t trewind __P((void));
+void   writerec __P((const void *dp, int isspcl));
+char   *mktimeest __P((time_t tnow));
+
+void   Exit __P((int status));
+void   dumpabort __P((int signo));
+void   getfstab __P((void));
+
+const char *rawname __P((const char *cp));
+struct dinode *getino __P((dump_ino_t inum));
+
+/* rdump routines */
+#ifdef RDUMP
+int    rmthost __P((const char *host));
+int    rmtopen __P((const char *tape, const int mode));
+void   rmtclose __P((void));
+int    rmtread __P((char *buf, size_t count));
+int    rmtwrite __P((const char *buf, size_t count));
+OFF_T  rmtseek __P((OFF_T offset, int pos));
+struct mtget * rmtstatus __P((void));
+int    rmtioctl __P((int cmd, int count));
+#endif /* RDUMP */
+
+void   interrupt __P((int signo));     /* in case operator bangs on console */
+int    exclude_ino __P((dump_ino_t ino));
+void   do_exclude_ino __P((dump_ino_t ino, const char *));
+
+/*
+ *     Exit status codes
+ */
+#define        X_FINOK         0       /* normal exit */
+#define        X_STARTUP       1       /* startup error */
+#define        X_REWRITE       2       /* restart writing from the check point */
+#define        X_ABORT         3       /* abort dump; don't attempt checkpointing */
+
+#define        OPGRENT "operator"              /* group entry to notify */
+#ifdef __linux__
+#define DIALUP "ttyS"                  /* prefix for dialups */
+#else
+#define DIALUP "ttyd"                  /* prefix for dialups */
+#endif
+
+#include <mntent.h>
+
+struct mntent *fstabsearch __P((const char *key));     /* search fs_file and fs_spec */
+#ifdef __linux__
+struct mntent *fstabsearchdir __P((const char *key, char *dir));       /* search fs_file and fs_spec */
+#endif
+
+/*
+ *     The contents of the file _PATH_DUMPDATES is maintained both on
+ *     a linked list, and then (eventually) arrayified.
+ */
+struct dumpdates {
+       char    dd_name[MAXPATHLEN+3];
+       struct mntent *dd_fstab;
+       int     dd_level;
+       time_t  dd_ddate;
+};
+struct dumptime {
+       struct  dumpdates dt_value;
+       struct  dumptime *dt_next;
+};
+extern struct  dumptime *dthead;       /* head of the list version */
+extern int     nddates;                /* number of records (might be zero) */
+extern int     ddates_in;              /* we have read the increment file */
+extern struct  dumpdates **ddatev;     /* the arrayfied version */
+void   initdumptimes __P((int));
+void   getdumptime __P((int));
+void   putdumptime __P((void));
+#define        ITITERATE(i, ddp) \
+       for (ddp = ddatev[i = 0]; i < nddates; ddp = ddatev[++i])
+
+void   sig __P((int signo));
+
+/*
+ * Compatibility with old systems.
+ */
+#ifdef COMPAT
+#include <sys/file.h>
+#define        strchr(a,b)     index(a,b)
+#define        strrchr(a,b)    rindex(a,b)
+extern char *strdup(), *ctime();
+extern int read(), write();
+extern int errno;
+#endif
+
+#ifdef __linux__
+#define        DUMP_CURRENT_REV        1
+
+int dump_fs_open(const char *disk, ext2_filsys *fs);
+#endif
+
+#ifndef        __linux__
+#ifndef        _PATH_UTMP
+#define        _PATH_UTMP      "/etc/utmp"
+#endif
+#ifndef        _PATH_FSTAB
+#define        _PATH_FSTAB     "/etc/fstab"
+#endif
+#endif
+
+#ifdef sunos
+extern char *calloc();
+extern char *malloc();
+extern long atol();
+extern char *strcpy();
+extern char *strncpy();
+extern char *strcat();
+extern time_t time();
+extern void endgrent();
+extern void exit();
+extern off_t lseek();
+extern const char *strerror();
+#endif
+
diff --git a/dump/itime.c b/dump/itime.c
new file mode 100644 (file)
index 0000000..f2cc763
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1980, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: itime.c,v 1.28 2004/06/17 09:01:15 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <time.h>
+#ifdef __linux__
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>
+#include <bsdcompat.h>
+#include <sys/file.h>
+#include <unistd.h>
+#elif defined sunos
+#include <sys/vnode.h>
+
+#include <ufs/fsdir.h>
+#include <ufs/inode.h>
+#include <ufs/fs.h>
+#else
+#include <ufs/ufs/dinode.h>
+#endif
+
+#include <protocols/dumprestore.h>
+
+#include "dump.h"
+
+struct dumpdates **ddatev;
+int    nddates;
+int    ddates_in;
+struct dumptime *dthead;
+
+static void dumprecout __P((FILE *, struct dumpdates *));
+static int getrecord __P((FILE *, struct dumpdates *));
+static int makedumpdate __P((struct dumpdates *, char *));
+static void readdumptimes __P((FILE *));
+
+void
+initdumptimes(int createdumpdates)
+{
+       FILE *df;
+       struct flock lock;
+
+       if ((df = fopen(dumpdates, "r")) == NULL) {
+               if (errno != ENOENT) {
+                       quit("cannot read %s: %s\n", dumpdates,
+                           strerror(errno));
+                       /* NOTREACHED */
+               }
+               if (createdumpdates) {
+                       /*
+                        * Dumpdates does not exist, make an empty one.
+                        */
+                       msg("WARNING: no file `%s', making an empty one\n", dumpdates);
+                       if ((df = fopen(dumpdates, "w")) == NULL) {
+                               quit("cannot create %s: %s\n", dumpdates,
+                               strerror(errno));
+                               /* NOTREACHED */
+                       }
+                       (void) fclose(df);
+                       if ((df = fopen(dumpdates, "r")) == NULL) {
+                               quit("cannot read %s even after creating it: %s\n",
+                               dumpdates, strerror(errno));
+                               /* NOTREACHED */
+                       }
+               }
+               else
+                       msg("WARNING: no file `%s'\n", dumpdates);
+       }
+       if (df != NULL) {
+               memset(&lock, 0, sizeof(lock));
+               lock.l_type = F_RDLCK;
+               if (fcntl(fileno(df), F_SETLKW, &lock) < 0)
+                       quit("cannot set read lock on %s: %s\n",
+                               dumpdates, strerror(errno));
+               readdumptimes(df);
+               (void) fclose(df);
+       }
+}
+
+static void
+readdumptimes(FILE *df)
+{
+       int i;
+       struct  dumptime *dtwalk;
+
+       for (;;) {
+               dtwalk = (struct dumptime *)calloc(1, sizeof (struct dumptime));
+               if (getrecord(df, &(dtwalk->dt_value)) < 0)
+                       break;
+               nddates++;
+               dtwalk->dt_next = dthead;
+               dthead = dtwalk;
+       }
+
+       ddates_in = 1;
+       /*
+        *      arrayify the list, leaving enough room for the additional
+        *      record that we may have to add to the ddate structure
+        */
+       ddatev = (struct dumpdates **)
+               calloc((unsigned) (nddates + 1), sizeof (struct dumpdates *));
+       dtwalk = dthead;
+       for (i = nddates - 1; i >= 0; i--, dtwalk = dtwalk->dt_next)
+               ddatev[i] = &dtwalk->dt_value;
+}
+
+void
+getdumptime(int createdumpdates)
+{
+       struct dumpdates *ddp;
+       int i;
+
+#ifdef FDEBUG
+       msg("Looking for name %s in dumpdates = %s for level = %s\n",
+               disk, dumpdates, level);
+#endif
+       spcl.c_ddate = 0;
+       memset(&lastlevel, 0, NUM_STR_SIZE);
+
+       /* If this is a level 0 dump, and we're not updating 
+          dumpdates, there's no point in trying to read
+          dumpdates.  It may not exist yet, or may not be mounted.  For
+          incrementals, we *must* read dumpdates (fail if it's not there!) */
+       if ( (!strcmp(level, lastlevel)) && !createdumpdates)
+               return;
+       initdumptimes(createdumpdates);
+       if (ddatev == NULL)
+               return;
+       /*
+        *      Go find the entry with the same name for a lower increment
+        *      and older date
+        */
+       ITITERATE(i, ddp) {
+               if (strncmp(disk, ddp->dd_name, sizeof (ddp->dd_name)) != 0)
+                       continue;
+               if (ddp->dd_level >= atoi(level))
+                       continue;
+               if (ddp->dd_ddate <= (time_t)spcl.c_ddate)
+                       continue;
+               spcl.c_ddate = ddp->dd_ddate;
+               snprintf(lastlevel, NUM_STR_SIZE, "%d", ddp->dd_level);
+       }
+}
+
+void
+putdumptime(void)
+{
+       FILE *df;
+       struct dumpdates *dtwalk;
+       int i;
+       int fd;
+       struct flock lock;
+
+       if(uflag == 0)
+               return;
+       if ((df = fopen(dumpdates, "r+")) == NULL)
+               quit("cannot rewrite %s: %s\n", dumpdates, strerror(errno));
+       fd = fileno(df);
+       memset(&lock, 0, sizeof(lock));
+       lock.l_type = F_WRLCK;
+       if (fcntl(fd, F_SETLKW, &lock) < 0)
+               quit("cannot set write lock on %s: %s\n", dumpdates, strerror(errno));
+       free((char *)ddatev);
+       ddatev = 0;
+       nddates = 0;
+       dthead = 0;
+       ddates_in = 0;
+       readdumptimes(df);
+       if (fseek(df, 0L, 0) < 0)
+               quit("fseek: %s\n", strerror(errno));
+       spcl.c_ddate = 0;
+       ITITERATE(i, dtwalk) {
+               if (strncmp(disk, dtwalk->dd_name,
+                               sizeof (dtwalk->dd_name)) != 0)
+                       continue;
+               if (dtwalk->dd_level != atoi(level))
+                       continue;
+               goto found;
+       }
+       /*
+        *      construct the new upper bound;
+        *      Enough room has been allocated.
+        */
+       dtwalk = ddatev[nddates] =
+               (struct dumpdates *)calloc(1, sizeof (struct dumpdates));
+       nddates += 1;
+  found:
+       (void) strncpy(dtwalk->dd_name, disk, sizeof (dtwalk->dd_name));
+       dtwalk->dd_level = atoi(level);
+       dtwalk->dd_ddate = spcl.c_date;
+
+       ITITERATE(i, dtwalk) {
+               dumprecout(df, dtwalk);
+       }
+       if (fflush(df))
+               quit("%s: %s\n", dumpdates, strerror(errno));
+       if (ftruncate(fd, ftell(df)))
+               quit("ftruncate (%s): %s\n", dumpdates, strerror(errno));
+       (void) fclose(df);
+}
+
+static void
+dumprecout(FILE *file, struct dumpdates *what)
+{
+       char buf[26];
+       struct tm *tms;
+
+       tms = localtime(&what->dd_ddate);
+       strncpy(buf, asctime(tms), sizeof(buf));
+       if (buf[24] != '\n' || buf[25] != '\0')
+               quit("asctime returned an unexpected string\n");
+       buf[24] = 0;
+       if (fprintf(file, "%s %d %s %c%2.2d%2.2d\n",
+                   what->dd_name,
+                   what->dd_level,
+                   buf,
+                   (tms->tm_gmtoff < 0 ? '-' : '+'),
+                   abs(tms->tm_gmtoff) / 3600,
+                   abs(tms->tm_gmtoff) % 3600 / 60) < 0)
+               quit("%s: %s\n", dumpdates, strerror(errno));
+}
+
+int    recno;
+
+static int
+getrecord(FILE *df, struct dumpdates *ddatep)
+{
+       char tbuf[BUFSIZ];
+
+       recno = 0;
+       if (fgets(tbuf, sizeof (tbuf), df) == NULL)
+               return(-1);
+       recno++;
+       if (makedumpdate(ddatep, tbuf) < 0) {
+               msg("Unknown format in %s, line %d\n",
+                       dumpdates, recno);
+               return(-1);
+       }
+
+#ifdef FDEBUG
+       msg("getrecord: %s %d %s", ddatep->dd_name, ddatep->dd_level,
+           ddatep->dd_ddate == 0 ? "the epoch\n" : ctime(&ddatep->dd_ddate));
+#endif
+       return(0);
+}
+
+static int
+makedumpdate(struct dumpdates *ddp, char *tbuf)
+{
+       char *tok;
+       /* device name */
+       if ( NULL == (tok = strsep( &tbuf, " ")) )
+               return(-1);
+       if ( !tbuf || strlen(tok) >  MAXPATHLEN )
+               return(-1);
+       strcpy(ddp->dd_name, tok);
+
+       /* eat whitespace */
+       for( ; *tbuf == ' ' ; tbuf++);
+
+       /* dump level */
+       ddp->dd_level = atoi(tbuf);
+       /* eat the rest of the numbers*/
+       for( ; *tbuf >= '0' && *tbuf <= '9' ; tbuf++);
+
+       /* eat whitespace */
+       for( ; *tbuf == ' ' ; tbuf++);
+
+       /* dump date */
+       ddp->dd_ddate = unctime(tbuf);
+       if (ddp->dd_ddate < 0)
+               return(-1);
+       /* fstab entry */
+       ddp->dd_fstab = fstabsearch(ddp->dd_name);
+       return(0);
+}
diff --git a/dump/main.c b/dump/main.c
new file mode 100644 (file)
index 0000000..b73a788
--- /dev/null
@@ -0,0 +1,1399 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1980, 1991, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: main.c,v 1.94 2004/07/05 15:12:45 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <compatlfs.h>
+#include <ctype.h>
+#include <compaterr.h>
+#include <fcntl.h>
+#include <fstab.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <mntent.h>
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <time.h>
+#ifdef __linux__
+#include <linux/types.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>
+#include <sys/stat.h>
+#include <bsdcompat.h>
+#include <linux/fs.h>  /* for definition of BLKFLSBUF */
+#elif defined sunos
+#include <sys/vnode.h>
+
+#include <ufs/inode.h>
+#include <ufs/fs.h>
+#else
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+#endif
+
+#include <protocols/dumprestore.h>
+
+#include "dump.h"
+#include "pathnames.h"
+#include "bylabel.h"
+
+#ifndef SBOFF
+#define SBOFF (SBLOCK * DEV_BSIZE)
+#endif
+
+int abortifconnerr = 1;                /* set to 1 if lib dumprmt.o should exit on connection errors
+                                otherwise just print a message using msg */
+/*
+ * Dump maps used to describe what is to be dumped.
+ */
+int    mapsize;        /* size of the state maps */
+char   *usedinomap;    /* map of allocated inodes */
+char   *dumpdirmap;    /* map of directories to be dumped */
+char   *dumpinomap;    /* map of files to be dumped */
+char   *metainomap;    /* which of the inodes in dumpinomap will get
+                          only their metadata dumped */
+
+const char *disk;      /* name of the disk file */
+char   tape[MAXPATHLEN];/* name of the tape file */
+char   *tapeprefix;    /* prefix of the tape file */
+char   *dumpdates;     /* name of the file containing dump date information*/
+char   lastlevel[NUM_STR_SIZE];/* dump level of previous dump */
+char   level[NUM_STR_SIZE];/* dump level of this dump */
+int    zipflag;        /* which compression method */
+int    Afile = -1;     /* archive file descriptor */
+int    AfileActive = 1;/* Afile flag */
+int    uflag;          /* update flag */
+int    mflag;          /* dump metadata only if possible */
+int    Mflag;          /* multi-volume flag */
+int    qflag;          /* quit on errors flag */
+int    vflag;          /* verbose flag */
+int     breademax = 32; /* maximum number of bread errors before we quit */
+char   *eot_script;    /* end of volume script fiag */
+int    diskfd;         /* disk file descriptor */
+int    tapefd;         /* tape file descriptor */
+int    pipeout;        /* true => output to standard output */
+int    fifoout;        /* true => output to fifo */
+dump_ino_t curino;     /* current inumber; used globally */
+int    newtape;        /* new tape flag */
+int    density;        /* density in 0.1" units */
+long   tapesize;       /* estimated tape size, blocks */
+long   tsize;          /* tape size in 0.1" units */
+long   asize;          /* number of 0.1" units written on current tape */
+int    etapes;         /* estimated number of tapes */
+int    nonodump;       /* if set, do not honor UF_NODUMP user flags */
+int    unlimited;      /* if set, write to end of medium */
+int    compressed;     /* if set, dump is to be compressed */
+long long bytes_written;/* total bytes written to tape */
+long   uncomprblks;    /* uncompressed blocks written to tape */
+int    notify;         /* notify operator flag */
+int    blockswritten;  /* number of blocks written on current tape */
+int    tapeno;         /* current tape number */
+time_t tstart_writing; /* when started writing the first tape block */
+time_t tend_writing;   /* after writing the last tape block */
+#ifdef __linux__
+ext2_filsys fs;
+#else
+struct fs *sblock;     /* the file system super block */
+char   sblock_buf[MAXBSIZE];
+#endif
+long   xferrate;       /* averaged transfer rate of all volumes */
+long   dev_bsize;      /* block size of underlying disk device */
+int    dev_bshift;     /* log2(dev_bsize) */
+int    tp_bshift;      /* log2(TP_BSIZE) */
+dump_ino_t volinfo[TP_NINOS];/* which inode on which volume archive info */
+
+#ifdef USE_QFA
+int    gTapeposfd;
+char   *gTapeposfile;
+char   gTps[255];
+int32_t        gThisDumpDate;
+#endif /* USE_QFA */
+
+struct dumptime *dthead;       /* head of the list version */
+int    nddates;                /* number of records (might be zero) */
+int    ddates_in;              /* we have read the increment file */
+struct dumpdates **ddatev;     /* the arrayfied version */
+
+int    notify = 0;     /* notify operator flag */
+int    blockswritten = 0;      /* number of blocks written on current tape */
+int    tapeno = 0;     /* current tape number */
+int    density = 0;    /* density in bytes/0.1" " <- this is for hilit19 */
+int    ntrec = NTREC;  /* # blocks in each tape record */
+int    cartridge = 0;  /* Assume non-cartridge tape */
+#ifdef USE_QFA
+int    tapepos = 0;    /* assume no QFA tapeposition needed by user */
+#endif /* USE_QFA */
+int    dokerberos = 0; /* Use Kerberos authentication */
+long   dev_bsize = 1;  /* recalculated below */
+long   *blocksperfiles = NULL; /* output blocks per file(s) */
+char   *host = NULL;   /* remote host (if any) */
+int    sizest = 0;     /* return size estimate only */
+int    compressed = 0; /* use zlib to compress the output, compress level 1-9 */
+long long bytes_written = 0; /* total bytes written */
+long   uncomprblks = 0;/* uncompressed blocks written */
+
+long smtc_errno;
+
+#ifdef __linux__
+char   *__progname;
+#endif
+
+int    maxbsize = 1024*1024;     /* XXX MAXBSIZE from sys/param.h */
+static long numarg __P((const char *, long, long));
+static long *numlistarg __P((const char *, long, long));
+static void obsolete __P((int *, char **[]));
+static void usage __P((void));
+static void do_exclude_from_file __P((char *));
+static void do_exclude_ino_str __P((char *));
+static void incompat_flags __P((int, char, char));
+
+static char* iexclude_bitmap = NULL;           /* the inode exclude bitmap */
+static unsigned int iexclude_bitmap_bytes = 0; /* size of bitmap in bytes */
+
+int
+main(int argc, char *argv[])
+{
+       dump_ino_t ino;
+       int dirty;
+       struct dinode *dp;
+       struct mntent *dt;
+       char *map;
+       int ch, pch = 0;
+       int i, anydirskipped;
+       int aflag = 0, bflag = 0, Tflag = 0, honorlevel = 1;
+       dump_ino_t maxino;
+       struct STAT statbuf;
+       dev_t filedev = 0;
+#ifdef __linux__
+       errcode_t retval;
+       char directory[MAXPATHLEN];
+       char pathname[MAXPATHLEN];
+#endif
+       time_t tnow;
+       char *diskparam;
+       char *Apath = NULL;
+
+       spcl.c_label[0] = '\0';
+       spcl.c_date = time(NULL);
+
+#ifdef __linux__
+       __progname = argv[0];
+       directory[0] = 0;
+       initialize_ext2_error_table();
+#endif
+
+       tsize = 0;      /* Default later, based on 'c' option for cart tapes */
+       unlimited = 1;
+       eot_script = NULL;
+       if ((tapeprefix = getenv("TAPE")) == NULL)
+               tapeprefix = _PATH_DEFTAPE;
+       dumpdates = _PATH_DUMPDATES;
+       if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0)
+               quit("TP_BSIZE must be a multiple of DEV_BSIZE\n");
+       memset(&lastlevel, 0, NUM_STR_SIZE);
+       memset(&level, 0, NUM_STR_SIZE);
+
+       if (argc < 2)
+               usage();
+
+       obsolete(&argc, &argv);
+
+#ifdef USE_QFA
+       gTapeposfd = -1;
+#endif /* USE_QFA */
+
+       while ((ch = getopt(argc, argv,
+                           "0123456789A:aB:b:cd:D:e:E:f:F:h:I:"
+#ifdef HAVE_BZLIB
+                           "j::"
+#endif
+                           "L:"
+#ifdef KERBEROS
+                           "k"
+#endif
+                           "mMnq"
+#ifdef USE_QFA
+                           "Q:"
+#endif
+                           "s:ST:uvWw"
+#ifdef HAVE_LZO
+                           "y"
+#endif
+#ifdef HAVE_ZLIB
+                           "z::"
+#endif
+                           )) != -1)
+               switch (ch) {
+               /* dump level */
+               case '0': case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                       if ((pch >= '0') && (pch <= '9') && (strlen(level) < NUM_STR_SIZE))
+                               level[strlen(level)] = ch;
+                       else 
+                               level[0] = ch;
+                       pch = ch;
+                       break;
+
+               case 'A':               /* archive file */
+                       Apath = optarg;
+                       break;
+
+               case 'a':               /* `auto-size', Write to EOM. */
+                       unlimited = 1;
+                       aflag = 1;
+                       break;
+
+               case 'B':               /* blocks per output file */
+                       unlimited = 0;
+                       blocksperfiles = numlistarg("number of blocks per file",
+                           1L, 0L);
+                       break;
+
+               case 'b':               /* blocks per tape write */
+                       ntrec = numarg("number of blocks per write",
+                           1L, 1048576L);
+                       if (ntrec > maxbsize/1024) {
+                               msg("Please choose a blocksize <= %dkB\n",
+                                       maxbsize/1024);
+                               msg("The ENTIRE dump is aborted.\n");
+                               exit(X_STARTUP);
+                       }
+                       bflag = 1;
+                       break;
+
+               case 'c':               /* Tape is cart. not 9-track */
+                       unlimited = 0;
+                       cartridge = 1;
+                       break;
+
+               case 'd':               /* density, in bits per inch */
+                       unlimited = 0;
+                       density = numarg("density", 10L, 327670L) / 10;
+                       if (density >= 625 && !bflag)
+                               ntrec = HIGHDENSITYTREC;
+                       break;
+
+               case 'D':               /* path of dumpdates file */
+                       dumpdates = optarg;
+                       break;
+                       
+                                       /* 04-Feb-00 ILC */
+               case 'e':               /* exclude an inode */
+                       {
+                       char *p = optarg, *q;
+                       while ((q = strchr(p, ','))) {
+                               *q = '\0';
+                               do_exclude_ino_str(p);
+                               p = q + 1;
+                       }
+                       do_exclude_ino_str(p);
+                       }
+                       break;
+
+               case 'E':               /* exclude inodes read from file */
+                       do_exclude_from_file(optarg);
+                       break;
+
+               case 'f':               /* output file */
+                       tapeprefix = optarg;
+                       break;
+
+               case 'F':               /* end of tape script */
+                       eot_script = optarg;
+                       break;
+
+               case 'h':
+                       honorlevel = numarg("honor level", 0L, 10L);
+                       break;
+
+#ifdef HAVE_BZLIB
+               case 'j':
+                       compressed = 2;
+                       zipflag = COMPRESS_BZLIB;
+                       if (optarg)
+                               compressed = numarg("compress level", 1L, 9L);
+                       break;
+#endif /* HAVE_BZLIB */
+
+               case 'I':
+                       breademax =
+                         numarg ("number of errors to ignore", 0L, 0L);
+                       break;
+
+#ifdef KERBEROS
+               case 'k':
+                       dokerberos = 1;
+                       break;
+#endif
+
+               case 'L':
+                       /*
+                        * Note that although there are LBLSIZE characters,
+                        * the last must be '\0', so the limit on strlen()
+                        * is really LBLSIZE-1.
+                        */
+                       strncpy(spcl.c_label, optarg, LBLSIZE);
+                       spcl.c_label[LBLSIZE-1] = '\0';
+                       if (strlen(optarg) > LBLSIZE-1) {
+                               msg(
+               "WARNING Label `%s' is larger than limit of %d characters.\n",
+                                   optarg, LBLSIZE-1);
+                               msg("WARNING: Using truncated label `%s'.\n",
+                                   spcl.c_label);
+                       }
+                       break;
+
+               case 'm':               /* metadata only flag */
+                       mflag = 1;
+                       break;
+
+               case 'M':               /* multi-volume flag */
+                       Mflag = 1;
+                       break;
+
+               case 'n':               /* notify operators */
+                       notify = 1;
+                       break;
+
+               case 'q':
+                       qflag = 1;
+                       break;
+
+#ifdef USE_QFA
+               case 'Q':               /* create tapeposfile */
+                       gTapeposfile = optarg;
+                       tapepos = 1;
+                       break;
+#endif /* USE_QFA */
+                       
+               case 's':               /* tape size, feet */
+                       unlimited = 0;
+                       tsize = numarg("tape size", 1L, 0L) * 12 * 10;
+                       break;
+
+               case 'S':
+                       sizest = 1;     /* return size estimate only */
+                       break;
+
+               case 'T':               /* time of last dump */
+                       spcl.c_ddate = unctime(optarg);
+                       if (spcl.c_ddate < 0) {
+                               msg("bad time \"%s\"\n", optarg);
+                               msg("The ENTIRE dump is aborted.\n");
+                               exit(X_STARTUP);
+                       }
+                       Tflag = 1;
+                       lastlevel[0] = '?'; lastlevel[1] = '\0'; 
+                       break;
+
+               case 'u':               /* update dumpdates */
+                       uflag = 1;
+                       break;
+
+               case 'v':               /* verbose */
+                       vflag = 1;
+                       break;
+
+               case 'W':               /* what to do */
+               case 'w':
+                       lastdump(ch);
+                       exit(X_FINOK);  /* do nothing else */
+#ifdef HAVE_LZO
+               case 'y':
+                       compressed = 2;
+                       zipflag = COMPRESS_LZO;
+                       break;
+#endif /* HAVE_LZO */
+
+#ifdef HAVE_ZLIB
+               case 'z':
+                       compressed = 2;
+                       zipflag = COMPRESS_ZLIB;
+                       if (optarg)
+                               compressed = numarg("compress level", 1L, 9L);
+                       break;
+#endif /* HAVE_ZLIB */
+
+               default:
+                       usage();
+               }
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1) {
+               msg("Must specify disk or filesystem\n");
+               msg("The ENTIRE dump is aborted.\n");
+               exit(X_STARTUP);
+       }
+       diskparam = *argv++;
+       if (strlen(diskparam) >= MAXPATHLEN) {
+               msg("Disk or filesystem name too long: %s\n", diskparam);
+               msg("The ENTIRE dump is aborted.\n");
+               exit(X_STARTUP);
+       }
+       argc--;
+       incompat_flags(Tflag && uflag, 'T', 'u');
+       incompat_flags(aflag && blocksperfiles, 'a', 'B');
+       incompat_flags(aflag && cartridge, 'a', 'c');
+       incompat_flags(aflag && density, 'a', 'd');
+       incompat_flags(aflag && tsize, 'a', 's');
+
+       if (strcmp(tapeprefix, "-") == 0) {
+               pipeout++;
+               tapeprefix = "standard output";
+       }
+
+       if (blocksperfiles && !compressed)
+               for (i = 1; i <= *blocksperfiles; i++)
+                       blocksperfiles[i] = blocksperfiles[i] / ntrec * ntrec; /* round down */
+       else if (!unlimited) {
+               /*
+                * Determine how to default tape size and density
+                *
+                *              density                         tape size
+                * 9-track      1600 bpi (160 bytes/.1")        2300 ft.
+                * 9-track      6250 bpi (625 bytes/.1")        2300 ft.
+                * cartridge    8000 bpi (100 bytes/.1")        1700 ft.
+                *                                              (450*4 - slop)
+                * hilit19 hits again: "
+                */
+               if (density == 0)
+                       density = cartridge ? 100 : 160;
+               if (tsize == 0)
+                       tsize = cartridge ? 1700L*120L : 2300L*120L;
+       }
+
+       {
+               int i;
+               char *n;
+
+               if ((n = strchr(tapeprefix, ':'))) {
+                       for (i = 0; i < (n - tapeprefix); i++) {
+                               if (tapeprefix[i] == '/')
+                                       break;
+                       }
+                       if (tapeprefix[i] != '/') {
+                               host = tapeprefix;
+                               tapeprefix = strchr(host, ':');
+                               *tapeprefix++ = '\0';
+#ifdef RDUMP
+                               if (index(tapeprefix, '\n')) {
+                                       msg("invalid characters in tape\n");
+                                       msg("The ENTIRE dump is aborted.\n");
+                                       exit(X_STARTUP);
+                               }
+                               if (rmthost(host) == 0)
+                                       exit(X_STARTUP);
+#else
+                               msg("remote dump not enabled\n");
+                               msg("The ENTIRE dump is aborted.\n");
+                               exit(X_STARTUP);
+#endif
+                       }
+               }
+       }
+
+       (void)setuid(getuid()); /* rmthost() is the only reason to be setuid */
+       if (Apath && (Afile = open(Apath, O_WRONLY|O_CREAT|O_TRUNC,
+                                  S_IRUSR | S_IWUSR | S_IRGRP |
+                                  S_IWGRP | S_IROTH | S_IWOTH)) < 0) {
+               msg("Cannot open %s for writing: %s\n",
+                   optarg, strerror(errno));
+               msg("The ENTIRE dump is aborted.\n");
+               exit(X_STARTUP);
+       }
+
+       if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+               signal(SIGHUP, sig);
+       if (signal(SIGTRAP, SIG_IGN) != SIG_IGN)
+               signal(SIGTRAP, sig);
+       if (signal(SIGFPE, SIG_IGN) != SIG_IGN)
+               signal(SIGFPE, sig);
+       if (signal(SIGBUS, SIG_IGN) != SIG_IGN)
+               signal(SIGBUS, sig);
+       if (signal(SIGSEGV, SIG_IGN) != SIG_IGN)
+               signal(SIGSEGV, sig);
+       if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+               signal(SIGTERM, sig);
+       if (signal(SIGINT, interrupt) == SIG_IGN)
+               signal(SIGINT, SIG_IGN);
+#ifdef SIGXCPU
+       signal(SIGXCPU, SIG_IGN);
+#endif /* SIGXCPU */
+#ifdef SIGXFSZ
+       signal(SIGXFSZ, SIG_IGN);
+#endif /* SIGXFSZ */
+
+       set_operators();        /* /etc/group snarfed */
+       getfstab();             /* /etc/fstab snarfed */
+
+       /*
+        *      disk may end in / and this can confuse
+        *      fstabsearch.
+        */
+       i = strlen(diskparam) - 1;
+       if (i > 1 && diskparam[i] == '/')
+               if (!(i == 6 && !strcmp(diskparam, "LABEL=/")))
+                       diskparam[i] = '\0';
+
+       disk = get_device_name(diskparam);
+       if (!disk)
+               disk = strdup(diskparam);
+
+       /*
+        *      disk can be either the full special file name,
+        *      the suffix of the special file name,
+        *      the special name missing the leading '/',
+        *      the file system name with or without the leading '/'.
+        */
+       if ((dt = fstabsearch(disk)) != NULL) {
+               /* if found then only one parameter (i.e. partition)
+                * is allowed */
+               if (argc >= 1) {
+                       (void)fprintf(stderr, "Unknown arguments to dump:");
+                       while (argc--)
+                               (void)fprintf(stderr, " %s", *argv++);
+                       (void)fprintf(stderr, "\n");
+                       msg("The ENTIRE dump is aborted.\n");
+                       exit(X_STARTUP);
+               }
+               disk = rawname(dt->mnt_fsname);
+               (void)strncpy(spcl.c_dev, dt->mnt_fsname, NAMELEN);
+               (void)strncpy(spcl.c_filesys, dt->mnt_dir, NAMELEN);
+       } else {
+#ifdef __linux__
+#ifdef HAVE_REALPATH
+               if (realpath(disk, pathname) == NULL)
+#endif
+                       strcpy(pathname, disk);
+               /*
+                * The argument could be now a mountpoint of
+                * a filesystem specified in fstab. Search for it.
+                */
+               if ((dt = fstabsearch(pathname)) != NULL) {
+                       disk = rawname(dt->mnt_fsname);
+                       (void)strncpy(spcl.c_dev, dt->mnt_fsname, NAMELEN);
+                       (void)strncpy(spcl.c_filesys, dt->mnt_dir, NAMELEN);
+               } else {
+                       /*
+                        * The argument was not found in the fstab
+                        * assume that this is a subtree and search for it
+                        */
+                       dt = fstabsearchdir(pathname, directory);
+                       if (dt != NULL) {
+                               char name[MAXPATHLEN];
+                               (void)strncpy(spcl.c_dev, dt->mnt_fsname, NAMELEN);
+                               (void)snprintf(name, sizeof(name), "%s (dir %s)",
+                                             dt->mnt_dir, directory);
+                               (void)strncpy(spcl.c_filesys, name, NAMELEN);
+                               disk = rawname(dt->mnt_fsname);
+                       } else {
+                               (void)strncpy(spcl.c_dev, disk, NAMELEN);
+                               (void)strncpy(spcl.c_filesys, "an unlisted file system",
+                                   NAMELEN);
+                       }
+               }
+#else
+               (void)strncpy(spcl.c_dev, disk, NAMELEN);
+               (void)strncpy(spcl.c_filesys, "an unlisted file system",
+                   NAMELEN);
+#endif
+       }
+
+       if (directory[0] != 0) {
+               if (atoi(level) != 0) {
+                       msg("Only level 0 dumps are allowed on a subdirectory\n");
+                       msg("The ENTIRE dump is aborted.\n");
+                       exit(X_STARTUP);
+               }
+               if (uflag) {
+                       msg("You can't update the dumpdates file when dumping a subdirectory\n");
+                       msg("The ENTIRE dump is aborted.\n");
+                       exit(X_STARTUP);
+               }
+       }
+       spcl.c_dev[NAMELEN-1] = '\0';
+       spcl.c_filesys[NAMELEN-1] = '\0';
+       (void)gethostname(spcl.c_host, NAMELEN);
+       spcl.c_host[NAMELEN-1] = '\0';
+       spcl.c_level = atoi(level);
+       spcl.c_type = TS_TAPE;
+       if (!Tflag)
+               getdumptime(uflag);             /* dumpdates snarfed */
+
+       if (spcl.c_ddate == 0 && spcl.c_level) {
+               msg("WARNING: There is no inferior level dump on this filesystem\n"); 
+               msg("WARNING: Assuming a level 0 dump by default\n");
+               level[0] = '0'; level[1] = '\0';
+               spcl.c_level = 0;
+       }
+
+       if (Mflag)
+               snprintf(tape, MAXPATHLEN, "%s%03d", tapeprefix, tapeno + 1);
+       else
+               strncpy(tape, tapeprefix, MAXPATHLEN);
+       tape[MAXPATHLEN - 1] = '\0';
+
+       if (!pipeout) {
+               if (STAT(tape, &statbuf) != -1)
+                       fifoout= statbuf.st_mode & S_IFIFO;
+       }
+
+       if (!sizest) {
+
+               msg("Date of this level %s dump: %s", level,
+                   ctime4(&spcl.c_date));
+#ifdef USE_QFA
+               gThisDumpDate = spcl.c_date;
+#endif
+               if (spcl.c_ddate)
+                       msg("Date of last level %s dump: %s", lastlevel,
+                           ctime4(&spcl.c_ddate));
+               msg("Dumping %s (%s) ", disk, spcl.c_filesys);
+               if (host)
+                       msgtail("to %s on host %s\n", tape, host);
+               else
+                       msgtail("to %s\n", tape);
+       } /* end of size estimate */
+
+#ifdef __linux__
+       if ((diskfd = OPEN(disk, O_RDONLY)) < 0) {
+               msg("Cannot open %s\n", disk);
+               msg("The ENTIRE dump is aborted.\n");
+               exit(X_STARTUP);
+       }
+#ifdef BLKFLSBUF
+       (void)ioctl(diskfd, BLKFLSBUF, 0);
+#endif
+       retval = dump_fs_open(disk, &fs);
+       if (retval) {
+               com_err(disk, retval, "while opening filesystem");
+               if (retval == EXT2_ET_REV_TOO_HIGH)
+                       msg("Get a newer version of dump!\n");
+               msg("The ENTIRE dump is aborted.\n");
+               exit(X_STARTUP);
+       }
+       if (fs->super->s_rev_level > DUMP_CURRENT_REV) {
+               com_err(disk, retval, "while opening filesystem");
+               msg("Get a newer version of dump!\n");
+               msg("The ENTIRE dump is aborted.\n");
+               exit(X_STARTUP);
+       }
+       /* if no user label specified, use ext2 filesystem label if available */
+       if (spcl.c_label[0] == '\0') {
+               const char *lbl;
+               if ( (lbl = get_device_label(disk)) != NULL) {
+                       strncpy(spcl.c_label, lbl, LBLSIZE);
+                       spcl.c_label[LBLSIZE-1] = '\0';
+               }
+               else
+                       strcpy(spcl.c_label, "none");   /* safe strcpy. */
+       }
+       sync();
+       dev_bsize = DEV_BSIZE;
+       dev_bshift = ffs(dev_bsize) - 1;
+       if (dev_bsize != (1 << dev_bshift))
+               quit("dev_bsize (%d) is not a power of 2", dev_bsize);
+       tp_bshift = ffs(TP_BSIZE) - 1;
+       if (TP_BSIZE != (1 << tp_bshift))
+               quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
+       maxino = fs->super->s_inodes_count + 1;
+       spcl.c_flags |= DR_NEWINODEFMT;
+#else  /* __linux __*/
+       if ((diskfd = open(disk, O_RDONLY)) < 0) {
+               msg("Cannot open %s\n", disk);
+               msg("The ENTIRE dump is aborted.\n");
+               exit(X_STARTUP);
+       }
+       sync();
+       sblock = (struct fs *)sblock_buf;
+       bread(SBOFF, (char *) sblock, SBSIZE);
+       if (sblock->fs_magic != FS_MAGIC)
+               quit("bad sblock magic number\n");
+       dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1);
+       dev_bshift = ffs(dev_bsize) - 1;
+       if (dev_bsize != (1 << dev_bshift))
+               quit("dev_bsize (%d) is not a power of 2", dev_bsize);
+       tp_bshift = ffs(TP_BSIZE) - 1;
+       if (TP_BSIZE != (1 << tp_bshift))
+               quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
+#ifdef FS_44INODEFMT
+       if (sblock->fs_inodefmt >= FS_44INODEFMT)
+               spcl.c_flags |= DR_NEWINODEFMT;
+#endif
+       maxino = sblock->fs_ipg * sblock->fs_ncg;
+#endif /* __linux__ */
+       mapsize = roundup(howmany(maxino, NBBY), TP_BSIZE);
+       usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
+       dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char));
+       dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
+       metainomap = (char *)calloc((unsigned) mapsize, sizeof(char));
+       if (usedinomap == NULL || dumpdirmap == NULL || 
+           dumpinomap == NULL || metainomap == NULL)
+               quit("out of memory allocating inode maps\n");
+       tapesize = 2 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
+
+       nonodump = spcl.c_level < honorlevel;
+
+       if (!sizest) {
+               msg("Label: %s\n", spcl.c_label);
+               
+               msg("Writing %d Kilobyte records\n", ntrec);
+
+               if (compressed) {
+                       if (zipflag == COMPRESS_LZO) 
+                               msg("Compressing output (lzo)\n");
+                       else
+                               msg("Compressing output at compression level %d (%s)\n", 
+                                       compressed, zipflag == COMPRESS_ZLIB ? "zlib" : "bzlib");
+               }
+       }
+
+#if defined(SIGINFO)
+       (void)signal(SIGINFO, statussig);
+#endif
+
+       if (!sizest)
+               msg("mapping (Pass I) [regular files]\n");
+#ifdef __linux__
+       if (directory[0] == 0)
+               anydirskipped = mapfiles(maxino, &tapesize);
+       else {
+               if (LSTAT(pathname, &statbuf) == -1) {
+                       msg("File cannot be accessed (%s).\n", pathname);
+                       msg("The ENTIRE dump is aborted.\n");
+                       exit(X_STARTUP);
+               }
+               filedev = statbuf.st_dev;
+               if (!(statbuf.st_mode & S_IFDIR))       /* is a file */
+                       anydirskipped = maponefile(maxino, &tapesize, 
+                                                  directory);
+               else
+                       anydirskipped = mapfilesfromdir(maxino, &tapesize, 
+                                                       directory);
+       }
+       while (argc--) {
+               int anydirskipped2;
+               char *p = *argv;
+               /* check if file is available */
+               if (LSTAT(p, &statbuf) == -1) {
+                       msg("File cannot be accessed (%s).\n", p);
+                       msg("The ENTIRE dump is aborted.\n");
+                       exit(X_STARTUP);
+               }
+               /* check if file is on same unix partiton as the first 
+                * argument */
+               if (statbuf.st_dev != filedev) {
+                       msg("Files are not on same file system (%s).\n", p);
+                       msg("The ENTIRE dump is aborted.\n");
+                       exit(X_STARTUP);
+               }
+               /* check if file is a directory */
+               if (!(statbuf.st_mode & S_IFDIR))
+                       anydirskipped2 = maponefile(maxino, &tapesize, 
+                                                   p+strlen(dt->mnt_dir));
+               else
+                       /* read directory inodes.
+                        * NOTE: nested directories are not recognized 
+                        * so inodes may be umped twice!
+                        */
+                       anydirskipped2 = mapfilesfromdir(maxino, &tapesize, 
+                                                        p+strlen(dt->mnt_dir));
+               if (!anydirskipped)
+                       anydirskipped = anydirskipped2;
+               argv++;
+       }               
+#else
+       anydirskipped = mapfiles(maxino, &tapesize);
+#endif
+
+       if (!sizest)
+               msg("mapping (Pass II) [directories]\n");
+       while (anydirskipped) {
+               anydirskipped = mapdirs(maxino, &tapesize);
+       }
+
+       if (sizest) {
+               printf("%.0f\n", ((double)tapesize + 1 + ntrec) * TP_BSIZE);
+               exit(X_FINOK);
+       } /* stop here for size estimate */
+
+       if (pipeout || unlimited) {
+               tapesize += 1 + ntrec;  /* 1 map header + trailer blocks */
+               msg("estimated %ld blocks.\n", tapesize);
+       } else {
+               double fetapes;
+
+               if (blocksperfiles) {
+                       long tapesize_left;
+
+                       tapesize_left = tapesize;
+                       fetapes = 0;
+                       for (i = 1; i < *blocksperfiles && tapesize_left; i++) {
+                               fetapes++;
+                               if (tapesize_left > blocksperfiles[i])
+                                       tapesize_left -= blocksperfiles[i];
+                               else
+                                       tapesize_left = 0;
+                       }
+                       if (tapesize_left)
+                               fetapes += (double)tapesize_left / blocksperfiles[*blocksperfiles];
+               } else if (cartridge) {
+                       /* Estimate number of tapes, assuming streaming stops at
+                          the end of each block written, and not in mid-block.
+                          Assume no erroneous blocks; this can be compensated
+                          for with an artificially low tape size. */
+                       fetapes =
+                       (         (double) tapesize     /* blocks */
+                               * TP_BSIZE      /* bytes/block */
+                               * (1.0/density) /* 0.1" / byte " */
+                         +
+                                 (double) tapesize     /* blocks */
+                               * (1.0/ntrec)   /* streaming-stops per block */
+                               * 15.48         /* 0.1" / streaming-stop " */
+                       ) * (1.0 / tsize );     /* tape / 0.1" " */
+               } else {
+                       /* Estimate number of tapes, for old fashioned 9-track
+                          tape */
+                       int tenthsperirg = (density == 625) ? 3 : 7;
+                       fetapes =
+                       (         (double) tapesize     /* blocks */
+                               * TP_BSIZE      /* bytes / block */
+                               * (1.0/density) /* 0.1" / byte " */
+                         +
+                                 (double) tapesize     /* blocks */
+                               * (1.0/ntrec)   /* IRG's / block */
+                               * tenthsperirg  /* 0.1" / IRG " */
+                       ) * (1.0 / tsize );     /* tape / 0.1" " */
+               }
+               etapes = fetapes;               /* truncating assignment */
+               etapes++;
+               /* count the dumped inodes map on each additional tape */
+               tapesize += (etapes - 1) *
+                       (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
+               tapesize += etapes + ntrec;     /* headers + trailer blks */
+               msg("estimated %ld blocks on %3.2f tape(s).\n",
+                   tapesize, fetapes);
+       }
+
+#ifdef USE_QFA
+       if (tapepos) {
+               msg("writing QFA positions to %s\n", gTapeposfile);
+               if ((gTapeposfd = open(gTapeposfile,
+                                      O_WRONLY|O_CREAT|O_TRUNC,
+                                      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
+                                      | S_IROTH | S_IWOTH)) < 0)
+                       quit("can't open tapeposfile\n");
+               /* print QFA-file header */
+               snprintf(gTps, sizeof(gTps), "%s\n%s\n%ld\n\n", QFA_MAGIC, QFA_VERSION, (unsigned long)spcl.c_date);
+               gTps[sizeof(gTps) - 1] = '\0';
+               if (write(gTapeposfd, gTps, strlen(gTps)) != (ssize_t)strlen(gTps))
+                       quit("can't write tapeposfile\n");
+               sprintf(gTps, "ino\ttapeno\ttapepos\n");
+               if (write(gTapeposfd, gTps, strlen(gTps)) != (ssize_t)strlen(gTps))
+                       quit("can't write tapeposfile\n");
+       }
+#endif /* USE_QFA */
+
+       /*
+        * Allocate tape buffer.
+        */
+       if (!alloctape())
+               quit(
+       "can't allocate tape buffers - try a smaller blocking factor.\n");
+
+       startnewtape(1);
+       tstart_writing = time(NULL);
+       dumpmap(usedinomap, TS_CLRI, maxino - 1);
+
+       msg("dumping (Pass III) [directories]\n");
+       dirty = 0;              /* XXX just to get gcc to shut up */
+       for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
+               if (((ino - 1) % NBBY) == 0)    /* map is offset by 1 */
+                       dirty = *map++;
+               else
+                       dirty >>= 1;
+               if ((dirty & 1) == 0)
+                       continue;
+               /*
+                * Skip directory inodes deleted and maybe reallocated
+                */
+               dp = getino(ino);
+               if ((dp->di_mode & IFMT) != IFDIR)
+                       continue;
+#ifdef __linux__
+               /*
+                * Skip directory inodes deleted and not yes reallocated...
+                */
+               if (dp->di_nlink == 0 || dp->di_dtime != 0)
+                       continue;
+               if (vflag)
+                       msg("dumping directory inode %lu\n", ino);
+               (void)dumpdirino(dp, ino);
+#else
+               (void)dumpino(dp, ino);
+#endif
+       }
+
+       msg("dumping (Pass IV) [regular files]\n");
+       for (map = dumpinomap, ino = 1; ino < maxino; ino++) {
+               if (((ino - 1) % NBBY) == 0)    /* map is offset by 1 */
+                       dirty = *map++;
+               else
+                       dirty >>= 1;
+               if ((dirty & 1) == 0)
+                       continue;
+               /*
+                * Skip inodes deleted and reallocated as directories.
+                */
+               dp = getino(ino);
+               if ((dp->di_mode & IFMT) == IFDIR)
+                       continue;
+#ifdef __linux__
+               /*
+                * No need to check here for deleted and not yet reallocated
+                * inodes since this is done in dumpino().
+                */
+#endif
+               if (vflag) {
+                       if (mflag && TSTINO(ino, metainomap))
+                               msg("dumping regular inode %lu (meta only)\n", ino);
+                       else
+                               msg("dumping regular inode %lu\n", ino);
+               }
+               (void)dumpino(dp, ino, mflag && TSTINO(ino, metainomap));
+       }
+
+       tend_writing = time(NULL);
+       spcl.c_type = TS_END;
+
+       if (Afile >= 0) {
+               volinfo[1] = ROOTINO;
+               memcpy(spcl.c_inos, volinfo, TP_NINOS * sizeof(dump_ino_t));
+               spcl.c_flags |= DR_INODEINFO;
+       }
+
+       /*
+        * Finish off the current tape record with trailer blocks, to ensure
+        * at least the data in the last partial record makes it to tape.
+        * Also make sure we write at least 1 trailer block.
+        */
+       for (i = ntrec - (spcl.c_tapea % ntrec); i; --i)
+               writeheader(maxino - 1);
+
+       tnow = trewind();
+
+       if (pipeout || fifoout)
+               msg("%ld blocks (%.2fMB)\n", spcl.c_tapea,
+                       ((double)spcl.c_tapea * TP_BSIZE / 1048576));
+       else
+               msg("%ld blocks (%.2fMB) on %d volume(s)\n",
+                   spcl.c_tapea, 
+                   ((double)spcl.c_tapea * TP_BSIZE / 1048576),
+                   spcl.c_volume);
+
+       /* report dump performance, avoid division by zero */
+       if (tend_writing - tstart_writing == 0)
+               msg("finished in less than a second\n");
+       else
+               msg("finished in %d seconds, throughput %d kBytes/sec\n",
+                   tend_writing - tstart_writing,
+                   spcl.c_tapea / (tend_writing - tstart_writing));
+
+       putdumptime();
+       msg("Date of this level %s dump: %s", level,
+               spcl.c_date == 0 ? "the epoch\n" : ctime4(&spcl.c_date));
+       msg("Date this dump completed:  %s", ctime(&tnow));
+
+       msg("Average transfer rate: %ld kB/s\n", xferrate / tapeno);
+       if (compressed) {
+               long tapekb = bytes_written / 1024;
+               double rate = .0005 + (double) spcl.c_tapea / tapekb;
+               msg("Wrote %ldkB uncompressed, %ldkB compressed, %1.3f:1\n",
+                       spcl.c_tapea, tapekb, rate);
+       }
+
+       if (Afile >= 0)
+               msg("Archiving dump to %s\n", Apath);
+
+       broadcast("DUMP IS DONE!\7\7\n");
+       msg("DUMP IS DONE\n");
+       Exit(X_FINOK);
+       /* NOTREACHED */
+       return 0;       /* gcc - shut up */
+}
+
+static void
+usage(void)
+{
+       char white[MAXPATHLEN];
+       const char *ext2ver, *ext2date;
+
+       memset(white, ' ', MAXPATHLEN);
+       white[MIN(strlen(__progname), MAXPATHLEN - 1)] = '\0';
+
+#ifdef __linux__
+       ext2fs_get_library_version(&ext2ver, &ext2date);
+       fprintf(stderr, "%s %s (using libext2fs %s of %s)\n",
+               __progname, _DUMP_VERSION, ext2ver, ext2date);
+#else
+       fprintf(stderr, "%s %s\n", __progname, _DUMP_VERSION);
+#endif
+       fprintf(stderr,
+               "usage:\t%s [-level#] [-ac"
+#ifdef KERBEROS
+               "k"
+#endif
+               "mMnqSuv"
+               "] [-A file] [-B records] [-b blocksize]\n"
+               "\t%s [-d density] [-D file] [-e inode#,inode#,...] [-E file]\n"
+               "\t%s [-f file] [-h level] [-I nr errors] "
+#ifdef HAVE_BZLIB
+               "[-j zlevel] "
+#endif
+#ifdef USE_QFA
+               "[-Q file]\n"
+#endif
+               "\t%s [-s feet] "
+               "[-T date] "
+#ifdef HAVE_LZO
+               "[-y] "
+#endif
+#ifdef HAVE_ZLIB
+               "[-z zlevel] "
+#endif
+               "filesystem\n"
+               "\t%s [-W | -w]\n", 
+               __progname, white, white, white, __progname);
+       exit(X_STARTUP);
+}
+
+/*
+ * Pick up a numeric argument.  It must be nonnegative and in the given
+ * range (except that a vmax of 0 means unlimited).
+ */
+static long
+numarg(const char *meaning, long vmin, long vmax)
+{
+       char *p;
+       long val;
+
+       val = strtol(optarg, &p, 10);
+       if (*p)
+               errx(X_STARTUP, "illegal %s -- %s", meaning, optarg);
+       if (val < vmin || (vmax && val > vmax))
+               errx(X_STARTUP, "%s must be between %ld and %ld", meaning, vmin, vmax);
+       return (val);
+}
+
+/*
+ * The same as numarg, just that it expects a comma separated list of numbers
+ * and returns an array of longs with the first element containing the number
+ * values in that array.
+ */
+static long *
+numlistarg(const char *meaning, long vmin, long vmax)
+{
+       char *p;
+       long *vals,*curval;
+       long valnum;
+
+       p = optarg;
+       vals = NULL;
+       valnum = 0;
+       do {
+               valnum++;
+               if ( !(vals = realloc(vals, (valnum + 1) * sizeof(*vals))) )
+                       errx(X_STARTUP, "allocating memory failed");
+               curval = vals + valnum;
+               *curval = strtol(p, &p, 10);
+               if (*p && *p!=',')
+                       errx(X_STARTUP, "illegal %s -- %s", meaning, optarg);
+               if (*curval < vmin || (vmax && *curval > vmax))
+                       errx(X_STARTUP, "%s must be between %ld and %ld", meaning, vmin, vmax);
+               *vals = valnum;
+               if (*p) p++;
+       } while(*p);
+       return (vals);
+}
+
+void
+sig(int signo)
+{
+       switch(signo) {
+       case SIGALRM:
+       case SIGBUS:
+       case SIGFPE:
+       case SIGHUP:
+       case SIGTERM:
+       case SIGTRAP:
+               if (pipeout || fifoout)
+                       quit("Signal on pipe: cannot recover\n");
+               msg("Rewriting attempted as response to unknown signal: %d.\n", signo);
+               (void)fflush(stderr);
+               (void)fflush(stdout);
+               close_rewind();
+               exit(X_REWRITE);
+               /* NOTREACHED */
+       case SIGSEGV:
+               msg("SIGSEGV: ABORTING!\n");
+               (void)signal(SIGSEGV, SIG_DFL);
+               (void)kill(0, SIGSEGV);
+               /* NOTREACHED */
+       }
+}
+
+const char *
+rawname(const char *cp)
+{
+#ifdef __linux__
+       return cp;
+#else  /* __linux__ */
+       static char rawbuf[MAXPATHLEN];
+       char *dp = strrchr(cp, '/');
+
+       if (dp == NULL)
+               return (NULL);
+       (void)strncpy(rawbuf, cp, min(dp-cp, MAXPATHLEN - 1));
+       rawbuf[min(dp-cp, MAXPATHLEN-1)] = '\0';
+       (void)strncat(rawbuf, "/r", MAXPATHLEN - 1 - strlen(rawbuf));
+       (void)strncat(rawbuf, dp + 1, MAXPATHLEN - 1 - strlen(rawbuf));
+       return (rawbuf);
+#endif /* __linux__ */
+}
+
+/*
+ * obsolete --
+ *     Change set of key letters and ordered arguments into something
+ *     getopt(3) will like.
+ */
+static void
+obsolete(int *argcp, char **argvp[])
+{
+       int argc, flags;
+       char *ap, **argv, *flagsp=NULL, **nargv, *p=NULL;
+
+       /* Setup. */
+       argv = *argvp;
+       argc = *argcp;
+
+       /* Return if no arguments or first argument has leading dash. */
+       ap = argv[1];
+       if (argc == 1 || *ap == '-')
+               return;
+
+       /* Allocate space for new arguments. */
+       if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
+           (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
+               err(X_STARTUP, "malloc new args");
+
+       *nargv++ = *argv;
+       argv += 2;
+
+       for (flags = 0; *ap; ++ap) {
+               switch (*ap) {
+               case 'A':
+               case 'B':
+               case 'b':
+               case 'd':
+               case 'D':
+               case 'e':
+               case 'E':
+               case 'f':
+               case 'F':
+               case 'h':
+               case 'L':
+               case 'Q':
+               case 's':
+               case 'T':
+                       if (*argv == NULL) {
+                               warnx("option requires an argument -- %c", *ap);
+                               usage();
+                       }
+                       if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
+                               err(X_STARTUP, "malloc arg");
+                       nargv[0][0] = '-';
+                       nargv[0][1] = *ap;
+                       (void)strcpy(&nargv[0][2], *argv);
+                       ++argv;
+                       ++nargv;
+                       break;
+               default:
+                       if (!flags) {
+                               *p++ = '-';
+                               flags = 1;
+                       }
+                       *p++ = *ap;
+                       break;
+               }
+       }
+
+       /* Terminate flags. */
+       if (flags) {
+               *p = '\0';
+               *nargv++ = flagsp;
+       }
+
+       /* Copy remaining arguments. */
+       while ((*nargv++ = *argv++));
+
+       /* Update argument count. */
+       *argcp = nargv - *argvp - 1;
+}
+
+/*
+ * This tests whether an inode is in the exclude bitmap
+ */
+int
+exclude_ino(dump_ino_t ino)
+{
+       /* if the inode exclude bitmap exists and covers given inode */
+       if (iexclude_bitmap && iexclude_bitmap_bytes > ino / 8) {
+               /* then check this inode against it */
+               int idx = iexclude_bitmap[ino / 8];
+               if (idx & (1 << (ino % 8)))
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * This adds an inode to the exclusion bitmap if it isn't already there
+ */
+void
+do_exclude_ino(dump_ino_t ino, const char *reason)
+{
+       if (exclude_ino(ino))
+               return;
+
+       if (vflag) {
+               if (reason)
+                       msg("Excluding inode %u (%s) from dump\n", ino, reason);
+               else
+                       msg("Excluding inode %u from dump\n", ino);
+       }
+
+       /* check for enough mem; initialize */
+       if ((ino/8 + 1) > iexclude_bitmap_bytes) {
+               if (iexclude_bitmap_bytes == 0) {
+                       unsigned int j;
+                       iexclude_bitmap_bytes = 2 * (ino/8 + 1);
+                       iexclude_bitmap = (char*) malloc(iexclude_bitmap_bytes);
+                       if (iexclude_bitmap == NULL) {
+                               msg("allocating memory failed\n");
+                               exit(X_STARTUP);
+                       }
+                       for (j = 0; j < iexclude_bitmap_bytes; j++)
+                               iexclude_bitmap[j] = 0;
+               }
+               else {
+                       unsigned int oldsize = iexclude_bitmap_bytes;
+                       iexclude_bitmap_bytes *= 
+                               (ino / 8 + 1) / iexclude_bitmap_bytes + 1;
+                       iexclude_bitmap = (char*) realloc(iexclude_bitmap, 
+                               iexclude_bitmap_bytes);
+                       if (iexclude_bitmap == NULL) {
+                               msg("allocating memory failed\n");
+                               exit(X_STARTUP);
+                       }
+                       for( ; oldsize < iexclude_bitmap_bytes; oldsize++)
+                               iexclude_bitmap[oldsize] = 0;
+               }
+       }
+               
+       iexclude_bitmap[ino / 8] |= 1 << (ino % 8);
+}
+
+static void
+do_exclude_ino_str(char * ino) {
+       char *r;
+       unsigned long inod;
+
+       inod = strtoul(ino, &r, 10);
+       if (( *r != '\0' && !isspace(*r) ) || inod <= ROOTINO) {
+               msg("Invalid inode argument %s\n", ino);
+               msg("The ENTIRE dump is aborted.\n");
+               exit(X_STARTUP);
+       }
+       do_exclude_ino(inod, NULL);
+}
+
+/*
+ * This reads a file containing one inode number per line and exclude them all
+ */
+static void 
+do_exclude_from_file(char *file) {
+       FILE *f;
+       char *p, fname[MAXPATHLEN];
+       
+
+       if (!( f = fopen(file, "r")) ) {
+               msg("Cannot open file for reading: %s\n", file);
+               msg("The ENTIRE dump is aborted.\n");
+               exit(X_STARTUP);
+       }
+       while (( p = fgets(fname, MAXPATHLEN, f))) {
+               if ( *p && *(p + strlen(p) - 1) == '\n' ) /* possible null string */
+                       *(p + strlen(p) - 1) = '\0';
+               if ( !*p ) /* skip empty lines */
+                       continue;
+               do_exclude_ino_str(p);
+       }
+       fclose(f);
+}
+
+static void incompat_flags(int cond, char flag1, char flag2) {
+       if (cond) {
+               msg("You cannot use the %c and %c flags together.\n", 
+                   flag1, flag2);
+               msg("The ENTIRE dump is aborted.\n");
+               exit(X_STARTUP);
+       }
+}
diff --git a/dump/optr.c b/dump/optr.c
new file mode 100644 (file)
index 0000000..a4504da
--- /dev/null
@@ -0,0 +1,736 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1980, 1988, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: optr.c,v 1.39 2004/07/05 15:12:45 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <errno.h>
+#include <mntent.h>
+#include <paths.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <utmp.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>
+#include <bsdcompat.h>
+#include <signal.h>
+#endif
+
+#include "dump.h"
+#include "pathnames.h"
+#include "bylabel.h"
+
+static void alarmcatch __P((int));
+int    datesort __P((const void *, const void *));
+static void sendmes __P((const char *, const char *));
+
+/* List of filesystem types that we can dump (same ext2 on-disk format) */
+static char *fstypes[] = { "ext2", "ext3", "InterMezzo", NULL };
+
+/*
+ *     Query the operator; This previously-fascist piece of code
+ *     no longer requires an exact response.
+ *     It is intended to protect dump aborting by inquisitive
+ *     people banging on the console terminal to see what is
+ *     happening which might cause dump to croak, destroying
+ *     a large number of hours of work.
+ *
+ *     Every 2 minutes we reprint the message, alerting others
+ *     that dump needs attention.
+ */
+static int timeout;
+static const char *attnmessage;                /* attention message */
+
+int
+query(const char *question)
+{
+       char    replybuffer[64];
+       int     back, errcount;
+       FILE    *mytty;
+       time_t  firstprompt, when_answered;
+
+       if (qflag) {
+               msg("%s - forced abort\n", question);
+               dumpabort(0);
+               /* NOTREACHED */
+       }
+
+       firstprompt = time(NULL);
+
+       if ((mytty = fopen(_PATH_TTY, "r")) == NULL)
+               quit("fopen on %s fails: %s\n", _PATH_TTY, strerror(errno));
+       attnmessage = question;
+       timeout = 0;
+       alarmcatch(0);
+       back = -1;
+       errcount = 0;
+       do {
+               if (fgets(replybuffer, 63, mytty) == NULL) {
+                       clearerr(mytty);
+                       if (++errcount > 30)    /* XXX  ugly */
+                               quit("excessive operator query failures\n");
+               } else if (replybuffer[0] == 'y' || replybuffer[0] == 'Y') {
+                       back = 1;
+               } else if (replybuffer[0] == 'n' || replybuffer[0] == 'N') {
+                       back = 0;
+               } else {
+                       (void) fprintf(stderr,
+                           "  DUMP: \"Yes\" or \"No\"?\n");
+                       (void) fprintf(stderr,
+                           "  DUMP: %s: (\"yes\" or \"no\") ", question);
+               }
+       } while (back < 0);
+
+       /*
+        *      Turn off the alarm, and reset the signal to trap out..
+        */
+       (void) alarm(0);
+       if (signal(SIGALRM, sig) == SIG_IGN)
+               signal(SIGALRM, SIG_IGN);
+       (void) fclose(mytty);
+       when_answered = time(NULL);
+       /*
+        * Adjust the base for time estimates to ignore time we spent waiting
+        * for operator input.
+        */
+       if (tstart_writing != 0)
+               tstart_writing += (when_answered - firstprompt);
+       return(back);
+}
+
+char lastmsg[BUFSIZ];
+
+/*
+ *     Alert the console operator, and enable the alarm clock to
+ *     sleep for 2 minutes in case nobody comes to satisfy dump
+ */
+static void
+alarmcatch(UNUSED(int signo))
+{
+       int save_errno = errno;
+       if (notify == 0) {
+               if (timeout == 0)
+                       (void) fprintf(stderr,
+                           "  DUMP: %s: (\"yes\" or \"no\") ",
+                           attnmessage);
+               else
+                       msgtail("\7\7");
+       } else {
+               if (timeout) {
+                       msgtail("\n");
+                       broadcast("");          /* just print last msg */
+               }
+               (void) fprintf(stderr,"  DUMP: %s: (\"yes\" or \"no\") ",
+                   attnmessage);
+       }
+       signal(SIGALRM, alarmcatch);
+       (void) alarm(120);
+       timeout = 1;
+       errno = save_errno;
+}
+
+/*
+ *     Here if an inquisitive operator interrupts the dump program
+ */
+void
+interrupt(UNUSED(int signo))
+{
+       msg("Interrupt received.\n");
+       if (query("Do you want to abort dump?"))
+               dumpabort(0);
+}
+
+/*
+ *     The following variables and routines manage alerting
+ *     operators to the status of dump.
+ *     This works much like wall(1) does.
+ */
+struct group *gp;
+
+/*
+ *     Get the names from the group entry "operator" to notify.
+ */
+void
+set_operators(void)
+{
+       if (!notify)            /*not going to notify*/
+               return;
+       gp = getgrnam(OPGRENT);
+       (void) endgrent();
+       if (gp == NULL) {
+               msg("No group entry for %s.\n", OPGRENT);
+               notify = 0;
+               return;
+       }
+}
+
+struct tm *localclock;
+
+/*
+ *     We fork a child to do the actual broadcasting, so
+ *     that the process control groups are not messed up
+ */
+void
+broadcast(const char *message)
+{
+       time_t          clock;
+       FILE    *f_utmp;
+       struct  utmp    utmp;
+       char    **np;
+       int     pid, s;
+
+       if (!notify || gp == NULL)
+               return;
+
+       switch (pid = fork()) {
+       case -1:
+               return;
+       case 0:
+               break;
+       default:
+               while (wait(&s) != pid)
+                       continue;
+               return;
+       }
+
+       clock = time(NULL);
+       localclock = localtime(&clock);
+
+       if ((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) {
+               msg("Cannot open %s: %s\n", _PATH_UTMP, strerror(errno));
+               return;
+       }
+
+       while (!feof(f_utmp)) {
+               if (fread((char *) &utmp, sizeof (struct utmp), 1, f_utmp) != 1)
+                       break;
+               if (utmp.ut_name[0] == 0)
+                       continue;
+               for (np = gp->gr_mem; *np; np++) {
+                       if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0)
+                               continue;
+                       /*
+                        *      Do not send messages to operators on dialups
+                        */
+                       if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0)
+                               continue;
+#ifdef DEBUG
+                       msg("Message to %s at %s\n", *np, utmp.ut_line);
+#endif
+                       sendmes(utmp.ut_line, message);
+               }
+       }
+       (void) fclose(f_utmp);
+       Exit(0);        /* the wait in this same routine will catch this */
+       /* NOTREACHED */
+}
+
+static void
+sendmes(const char *tty, const char *message)
+{
+       char t[MAXPATHLEN], buf[BUFSIZ];
+       const char *cp;
+       int lmsg = 1;
+       FILE *f_tty;
+
+       (void) strcpy(t, _PATH_DEV);
+       (void) strncat(t, tty, sizeof t - strlen(_PATH_DEV) - 1);
+
+       if ((f_tty = fopen(t, "w")) != NULL) {
+               setbuf(f_tty, buf);
+               (void) fprintf(f_tty,
+                   "\n\
+\7\7\7Message from the dump program to all operators at %d:%02d ...\r\n\n\
+DUMP: NEEDS ATTENTION: ",
+                   localclock->tm_hour, localclock->tm_min);
+               for (cp = lastmsg; ; cp++) {
+                       if (*cp == '\0') {
+                               if (lmsg) {
+                                       cp = message;
+                                       if (!(cp && *cp != '\0'))
+                                               break;
+                                       lmsg = 0;
+                               } else
+                                       break;
+                       }
+                       if (*cp == '\n')
+                               (void) putc('\r', f_tty);
+                       (void) putc(*cp, f_tty);
+               }
+               (void) fclose(f_tty);
+       }
+}
+
+/*
+ *     print out an estimate of the amount of time left to do the dump
+ */
+
+time_t tschedule = 0;
+
+void
+timeest(void)
+{
+       time_t tnow = time(NULL);
+
+       if (tnow >= tschedule) {
+               char *buf = mktimeest(tnow);
+               tschedule = tnow + 300;
+               if (buf) {
+                       fprintf(stderr, "  DUMP: ");
+                       fwrite(buf, strlen(buf), 1, stderr);
+                       fflush(stderr);
+               }
+       }
+}
+
+void
+#ifdef __STDC__
+msg(const char *fmt, ...)
+#else
+msg(fmt, va_alist)
+       char *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+
+       (void) fprintf(stderr,"  DUMP: ");
+#ifdef TDEBUG
+       (void) fprintf(stderr, "pid=%d ", getpid());
+#endif
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void) vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       (void) fflush(stdout);
+       (void) fflush(stderr);
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void) vsnprintf(lastmsg, sizeof(lastmsg), fmt, ap);
+       va_end(ap);
+}
+
+void
+#ifdef __STDC__
+msgtail(const char *fmt, ...)
+#else
+msgtail(fmt, va_alist)
+       char *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void) vfprintf(stderr, fmt, ap);
+       va_end(ap);
+}
+
+void
+#ifdef __STDC__
+quit(const char *fmt, ...)
+#else
+quit(fmt, va_alist)
+       char *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+
+       (void) fprintf(stderr,"  DUMP: ");
+#ifdef TDEBUG
+       (void) fprintf(stderr, "pid=%d ", getpid());
+#endif
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void) vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       (void) fflush(stdout);
+       (void) fflush(stderr);
+       dumpabort(0);
+}
+
+/*
+ *     Tell the operator what has to be done;
+ *     we don't actually do it
+ */
+
+struct pfstab {
+       struct  pfstab *pf_next;
+       struct  dumpdates *pf_dd;
+       struct  mntent *pf_mntent;
+};
+
+static struct pfstab *table;
+
+static struct mntent *
+allocfsent(struct mntent *fs)
+{
+       struct mntent *new;
+       const char *disk;
+       struct stat buf, tabbuf;
+       struct pfstab *tabpf;
+       struct mntent *tabfs;
+
+       new = (struct mntent *)malloc(sizeof (*fs));
+       if (new == NULL)
+               quit("%s\n", strerror(errno));
+
+       /* Translade UUID=, LABEL= ... */
+       disk = get_device_name(fs->mnt_fsname);
+       if (disk == NULL)
+               disk = strdup(fs->mnt_fsname);
+
+       /* Discard non block devices */
+       if (stat(disk, &buf) != 0 || !S_ISBLK(buf.st_mode)) {
+               free(new);
+               return NULL;
+       }
+
+       /* Discard same major/minor devices */
+       for (tabpf = table; tabpf != NULL; tabpf = tabpf->pf_next) {
+               tabfs = tabpf->pf_mntent;
+               if (stat(tabfs->mnt_fsname, &tabbuf) != 0)
+                       /* should not happen */
+                       quit("Cannot access %s\n", tabfs->mnt_fsname);
+               if (tabbuf.st_rdev == buf.st_rdev) {
+                       free(new);
+                       /* Copy passno and freq from /etc/fstab because 
+                        * /etc/mtab does always have them as 0 0 */
+                       if (!tabfs->mnt_passno)
+                               tabfs->mnt_passno = fs->mnt_passno;
+                       if (!tabfs->mnt_freq)
+                               tabfs->mnt_freq = fs->mnt_freq;
+                       return NULL;
+               }
+       }
+               
+       if (strlen(fs->mnt_dir) > 1 && fs->mnt_dir[strlen(fs->mnt_dir) - 1] == '/')
+               fs->mnt_dir[strlen(fs->mnt_dir) - 1] = '\0';
+       if ((new->mnt_dir = strdup(fs->mnt_dir)) == NULL ||
+           (new->mnt_type = strdup(fs->mnt_type)) == NULL ||
+           (new->mnt_opts = strdup(fs->mnt_opts)) == NULL ||
+           (new->mnt_fsname = strdup(disk)) == NULL)
+               quit("%s\n", strerror(errno));
+       new->mnt_passno = fs->mnt_passno;
+       new->mnt_freq = fs->mnt_freq;
+       return (new);
+}
+
+void
+getfstab(void)
+{
+       struct mntent *fs;
+       struct pfstab *pf;
+       struct pfstab *pfold = NULL;
+       FILE *mntfp;
+       char *mnttables[] = { _PATH_MOUNTED, _PATH_MNTTAB, 0 };
+       int i;
+
+       for (i = 0; mnttables[i]; i++) {
+               mntfp = setmntent(mnttables[i], "r");
+               if (mntfp == NULL) {
+                       msg("Can't open %s for dump table information: %s\n",
+                           mnttables[i], strerror(errno));
+                       continue;
+               }
+               while ((fs = getmntent(mntfp)) != NULL) {
+                       fs = allocfsent(fs);
+                       if (!fs)
+                               continue;
+                       fs->mnt_passno = 0;
+                       if ((pf = (struct pfstab *)malloc(sizeof (*pf))) == NULL)
+                               quit("%s\n", strerror(errno));
+                       pf->pf_mntent = fs;
+                       pf->pf_next = NULL;
+       
+                       /* keep table in /etc/fstab order for use with -w and -W */
+                       if (pfold) {
+                               pfold->pf_next = pf;
+                               pfold = pf;
+                       } else
+                               pfold = table = pf;
+               }
+               (void) endmntent(mntfp);
+       }
+}
+
+/*
+ * Search in the fstab for a file name.
+ * This file name can be either the special or the path file name.
+ *
+ * The entries in the fstab are the BLOCK special names, not the
+ * character special names.
+ * The caller of fstabsearch assures that the character device
+ * is dumped (that is much faster)
+ *
+ * The file name can omit the leading '/'.
+ */
+struct mntent *
+fstabsearch(const char *key)
+{
+       struct pfstab *pf;
+       struct mntent *fs;
+       const char *rn;
+
+       for (pf = table; pf != NULL; pf = pf->pf_next) {
+               fs = pf->pf_mntent;
+               if (strcmp(fs->mnt_dir, key) == 0 ||
+                   strcmp(fs->mnt_fsname, key) == 0)
+                       return (fs);
+               rn = rawname(fs->mnt_fsname);
+               if (rn != NULL && strcmp(rn, key) == 0)
+                       return (fs);
+               if (key[0] != '/') {
+                       if (*fs->mnt_fsname == '/' &&
+                           strcmp(fs->mnt_fsname + 1, key) == 0)
+                               return (fs);
+                       if (*fs->mnt_dir == '/' &&
+                           strcmp(fs->mnt_dir + 1, key) == 0)
+                               return (fs);
+               }
+       }
+       return (NULL);
+}
+
+#ifdef __linux__
+struct mntent *
+fstabsearchdir(const char *key, char *directory)
+{
+       struct pfstab *pf;
+       struct mntent *fs;
+       struct mntent *found_fs = NULL;
+       unsigned int size = 0;
+       struct stat buf;
+
+       if (stat(key, &buf) == 0 && S_ISBLK(buf.st_mode))
+               return NULL;
+
+       for (pf = table; pf != NULL; pf = pf->pf_next) {
+               fs = pf->pf_mntent;
+               if (strlen(fs->mnt_dir) > size &&
+                   strlen(key) > strlen(fs->mnt_dir) &&
+                   strncmp(fs->mnt_dir, key, strlen(fs->mnt_dir)) == 0 &&
+                   (key[strlen(fs->mnt_dir)] == '/' ||
+                    fs->mnt_dir[strlen(fs->mnt_dir) - 1] == '/')) {
+                       found_fs = fs;
+                       size = strlen(fs->mnt_dir);
+               }
+       }
+       if (found_fs != NULL) {
+               /*
+                * Ok, we have found a fstab entry which matches the argument
+                * We have to split the argument name into:
+                * - a device name (from the fstab entry)
+                * - a directory name on this device
+                */
+               strcpy(directory, key + size);
+       }
+       return(found_fs);
+}
+#endif
+
+static void
+print_wmsg(char arg, int dumpme, const char *dev, int level,
+          const char *mtpt, time_t ddate)
+{
+#ifdef FDEBUG
+       printf("checking dev %s: lvl %d, mtpt %s\n", dev, level, mtpt);
+#endif
+       if (!dumpme && arg == 'w')
+               return;
+
+       (void) printf("%c %8s\t(%6s) Last dump: ",
+                     dumpme && (arg != 'w') ? '>' : ' ',
+                     dev,
+                     mtpt ? mtpt : "");
+
+       /*
+        * Check ddate > 365 to avoid issues with fs in stab but not dumpdates.
+        * Not a problem, because ddate is in seconds since the epoch anyways.
+        */
+       if (ddate > 365) {
+               char *date, *d;
+
+               date = (char *)ctime(&ddate);
+               d = strchr(date, '\n');
+               if (d) *d = '\0';
+               printf("Level %d, Date %s\n", level, date);
+       } else
+               printf("never\n");
+}
+
+/*
+ *     Tell the operator what to do
+ */
+void
+lastdump(char arg) /* w ==> just what to do; W ==> most recent dumps */
+{
+       struct pfstab *pf;
+       time_t tnow;
+
+       tnow = time(NULL);
+       getfstab();             /* /etc/fstab input */
+       initdumptimes(0);       /* dumpdates input */
+       if (ddatev == NULL && table == NULL) {
+               (void) printf("No %s or %s file found\n",
+                             _PATH_MNTTAB, dumpdates);
+               return;
+       }
+
+       if (arg == 'w')
+               (void) printf("Dump these file systems:\n");
+       else
+               (void) printf("Last dump(s) done (Dump '>' file systems):\n");
+
+       /* For files in dumpdates, get the last dump level and date */
+       if (ddatev != NULL) {
+               struct dumpdates *dtwalk = NULL;
+               int i;
+               char *lastname;
+
+               qsort((char *) ddatev, nddates, sizeof(struct dumpdates *), datesort);
+
+               lastname = "??";
+               ITITERATE(i, dtwalk) {
+                       struct mntent *dt;
+                       if (strncmp(lastname, dtwalk->dd_name,
+                               sizeof(dtwalk->dd_name)) == 0)
+                               continue;
+                       lastname = dtwalk->dd_name;
+                       if ((dt = dtwalk->dd_fstab) != NULL) {
+                               /* Overload fs_freq as dump level and
+                                * fs_passno as date, because we can't
+                                * change struct fstab format.
+                                * A positive fs_freq means this
+                                * filesystem needs to be dumped.
+                                */
+                               dt->mnt_passno = dtwalk->dd_ddate;
+                               if (dt->mnt_freq > 0 && (dtwalk->dd_ddate <
+                                   tnow - (dt->mnt_freq * 86400)))
+                                       dt->mnt_freq = dtwalk->dd_level;
+                               else
+                                       dt->mnt_freq = -dtwalk->dd_level;
+#ifdef FDEBUG
+                               printf("%s fs_freq set to %d\n", lastname,
+                                       dt->mnt_freq);
+#endif
+                       }
+               }
+       }
+
+       /* print in /etc/fstab order only those filesystem types we can dump */
+       for (pf = table; pf != NULL; pf = pf->pf_next) {
+               struct mntent *dt = pf->pf_mntent;
+               char **type;
+
+               for (type = fstypes; *type != NULL; type++) {
+                       if (strncmp(dt->mnt_type, *type,
+                                   sizeof(dt->mnt_type)) == 0) {
+                               const char *disk = get_device_name(dt->mnt_fsname);
+                               print_wmsg(arg, dt->mnt_freq > 0,
+                                          disk ? disk : dt->mnt_fsname,
+                                          dt->mnt_freq < 0 ? -dt->mnt_freq :
+                                                             dt->mnt_freq,
+                                          dt->mnt_dir,
+                                          dt->mnt_passno);
+                       }
+               }
+       }
+
+       /* print in /etc/dumpdates order if not in /etc/fstab */
+       if (ddatev != NULL) {
+               struct dumpdates *dtwalk = NULL;
+               char *lastname;
+               int i;
+
+               lastname = "??";
+               ITITERATE(i, dtwalk) {
+                       if (strncmp(lastname, dtwalk->dd_name,
+                               sizeof(dtwalk->dd_name)) == 0 ||
+                           dtwalk->dd_fstab != NULL)
+                               continue;
+                       lastname = dtwalk->dd_name;
+                       print_wmsg(arg, 0, dtwalk->dd_name,
+                                  dtwalk->dd_level, NULL, dtwalk->dd_ddate);
+               }
+       }
+}
+
+int
+datesort(const void *a1, const void *a2)
+{
+       struct dumpdates *d1 = *(struct dumpdates **)a1;
+       struct dumpdates *d2 = *(struct dumpdates **)a2;
+       int diff;
+
+       diff = strncmp(d1->dd_name, d2->dd_name, sizeof(d1->dd_name));
+       if (diff == 0)
+               return (d2->dd_ddate - d1->dd_ddate);
+       return (diff);
+}
diff --git a/dump/tape.c b/dump/tape.c
new file mode 100644 (file)
index 0000000..2df4d1e
--- /dev/null
@@ -0,0 +1,1495 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1980, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: tape.c,v 1.86 2004/07/07 11:07:29 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <compatlfs.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <compaterr.h>
+#include <system.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#else
+int    write(), read();
+#endif
+
+#ifdef __linux__
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h> /* for definition of BLKFLSBUF */
+#ifndef BLKFLSBUF      /* last resort... */
+#define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache.  */
+#endif
+#include <time.h>
+#endif
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/mtio.h>
+#ifdef __linux__
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>
+#include <sys/stat.h>
+#include <bsdcompat.h>
+#elif defined sunos
+#include <sys/vnode.h>
+
+#include <ufs/fs.h>
+#include <ufs/inode.h>
+#else
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+#endif /* __linux__ */
+
+#include <protocols/dumprestore.h>
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif /* HAVE_ZLIB */
+
+#ifdef HAVE_BZLIB
+#include <bzlib.h>
+#endif /* HAVE_BZLIB */
+
+#ifdef HAVE_LZO
+#include <minilzo.h>
+#endif /* HAVE_LZO */
+
+#include "dump.h"
+
+int    writesize;              /* size of malloc()ed buffer for tape */
+long   lastspclrec = -1;       /* tape block number of last written header */
+int    trecno = 0;             /* next record to write in current block */
+extern long *blocksperfiles;   /* number of blocks per output file(s) */
+long   blocksperfiles_current; /* current position in blocksperfiles */
+long   blocksthisvol;          /* number of blocks on current output file */
+extern int ntrec;              /* blocking factor on tape */
+extern int cartridge;
+char   *nexttape;
+extern  pid_t rshpid;
+int    eot_code = 1;
+long long tapea_bytes = 0;     /* bytes_written at start of current volume */
+static int magtapeout;         /* output is really a tape */
+
+static ssize_t dump_atomic_read __P((int, char *, size_t));
+static ssize_t dump_atomic_write __P((int, const char *, size_t));
+#ifdef WRITEDEBUG
+static void doslave __P((int, int, int));
+#else
+static void doslave __P((int, int));
+#endif
+static void enslave __P((void));
+static void flushtape __P((void));
+static void killall __P((void));
+static void rollforward __P((void));
+#ifdef USE_QFA
+static int GetTapePos __P((long long *));
+static int MkTapeString __P((struct s_spcl *, long long));
+#define FILESQFAPOS    20
+#endif
+
+/*
+ * Concurrent dump mods (Caltech) - disk block reading and tape writing
+ * are exported to several slave processes.  While one slave writes the
+ * tape, the others read disk blocks; they pass control of the tape in
+ * a ring via signals. The parent process traverses the filesystem and
+ * sends writeheader()'s and lists of daddr's to the slaves via pipes.
+ * The following structure defines the instruction packets sent to slaves.
+ */
+struct req {
+       ext2_loff_t dblk;
+       int count;
+};
+int reqsiz;
+
+struct slave_results {
+       ssize_t unclen;         /* uncompressed length */
+       ssize_t clen;           /* compressed length */
+};
+
+#define SLAVES 3               /* 1 slave writing, 1 reading, 1 for slack */
+struct slave {
+       int tapea;              /* header number at start of this chunk */
+       int count;              /* count to next header (used for TS_TAPE */
+                               /* after EOT) */
+       int inode;              /* inode that we are currently dealing with */
+       int fd;                 /* FD for this slave */
+       int pid;                /* PID for this slave */
+       int sent;               /* 1 == we've sent this slave requests */
+       int firstrec;           /* record number of this block */
+       char (*tblock)[TP_BSIZE]; /* buffer for data blocks */
+       struct req *req;        /* buffer for requests */
+} slaves[SLAVES+1];
+struct slave *slp;
+
+char   (*nextblock)[TP_BSIZE];
+
+static time_t tstart_volume;   /* time of volume start */ 
+static int tapea_volume;       /* value of spcl.c_tapea at volume start */
+
+int master;            /* pid of master, for sending error signals */
+int tenths;            /* length of tape overhead per block written */
+static int caught;     /* have we caught the signal to proceed? */
+static int ready;      /* have we reached the lock point without having */
+                       /* received the SIGUSR2 signal from the prev slave? */
+static sigjmp_buf jmpbuf;      /* where to jump to if we are ready when the */
+                       /* SIGUSR2 arrives from the previous slave */
+#ifdef USE_QFA
+static int gtperr = 0;
+#endif
+
+int
+alloctape(void)
+{
+       int pgoff = getpagesize() - 1;
+       char *buf;
+       int i;
+
+       writesize = ntrec * TP_BSIZE;
+       reqsiz = (ntrec + 1) * sizeof(struct req);
+       /*
+        * CDC 92181's and 92185's make 0.8" gaps in 1600-bpi start/stop mode
+        * (see DEC TU80 User's Guide).  The shorter gaps of 6250-bpi require
+        * repositioning after stopping, i.e, streaming mode, where the gap is
+        * variable, 0.30" to 0.45".  The gap is maximal when the tape stops.
+        */
+       if (!blocksperfiles && !unlimited)
+               tenths = (cartridge ? 16 : density == 625 ? 5 : 8);
+       else {
+               tenths = 0;
+               density = 1;
+       }
+       /*
+        * Allocate tape buffer contiguous with the array of instruction
+        * packets, so flushtape() can write them together with one write().
+        * Align tape buffer on page boundary to speed up tape write().
+        */
+       for (i = 0; i <= SLAVES; i++) {
+               buf = (char *)
+                   malloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE));
+               if (buf == NULL)
+                       return(0);
+               slaves[i].tblock = (char (*)[TP_BSIZE])
+#ifdef __linux__
+                   (((long)&buf[reqsiz] + pgoff) &~ pgoff);
+#else
+                   (((long)&buf[ntrec + 1] + pgoff) &~ pgoff);
+#endif
+               slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1;
+       }
+       slp = &slaves[0];
+       slp->count = 1;
+       slp->tapea = 0;
+       slp->firstrec = 0;
+       nextblock = slp->tblock;
+       return(1);
+}
+
+void
+writerec(const void *dp, int isspcl)
+{
+
+       slp->req[trecno].dblk = (ext2_loff_t)0;
+       slp->req[trecno].count = 1;
+       /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
+       *(union u_spcl *)(*(nextblock)) = *(union u_spcl *)dp;
+
+       /* Need to write it to the archive file */
+       if (! AfileActive && isspcl && (spcl.c_type == TS_END))
+               AfileActive = 1;
+       if (AfileActive && Afile >= 0) {
+               /* When we dump an inode which is not a directory,
+                * it means we ended the archive contents */
+               if (isspcl && (spcl.c_type == TS_INODE) &&
+                   ((spcl.c_dinode.di_mode & S_IFMT) != IFDIR))
+                       AfileActive = 0;
+               else {
+                       union u_spcl tmp;
+                       tmp = *(union u_spcl *)dp;
+                       /* Write the record, _uncompressed_ */
+                       if (isspcl) {
+                               tmp.s_spcl.c_flags &= ~DR_COMPRESSED;
+                               mkchecksum(&tmp);
+                       }
+                       if (write(Afile, &tmp, TP_BSIZE) != TP_BSIZE)
+                               msg("error writing archive file: %s\n", 
+                               strerror(errno));
+               }
+       }
+
+       nextblock++;
+       if (isspcl)
+               lastspclrec = spcl.c_tapea;
+       trecno++;
+       spcl.c_tapea++;
+       if (trecno >= ntrec)
+               flushtape();
+}
+
+void
+dumpblock(blk_t blkno, int size)
+{
+       int avail, tpblks;
+       ext2_loff_t dblkno;
+
+       dblkno = fsbtodb(sblock, blkno);
+       tpblks = size >> tp_bshift;
+       while ((avail = MIN(tpblks, ntrec - trecno)) > 0) {
+               slp->req[trecno].dblk = dblkno;
+               slp->req[trecno].count = avail;
+               trecno += avail;
+               spcl.c_tapea += avail;
+               if (trecno >= ntrec)
+                       flushtape();
+               dblkno += avail << (tp_bshift - dev_bshift);
+               tpblks -= avail;
+       }
+}
+
+int    nogripe = 0;
+
+static void
+tperror(int errnum)
+{
+
+       if (pipeout) {
+               msg("write error on %s: %s\n", tape, strerror(errnum));
+               quit("Cannot recover\n");
+               /* NOTREACHED */
+       }
+       msg("write error %d blocks into volume %d: %s\n", 
+           blocksthisvol, tapeno, strerror(errnum));
+       broadcast("DUMP WRITE ERROR!\n");
+       if (query("Do you want to rewrite this volume?")) {
+               msg("Closing this volume.  Prepare to restart with new media;\n");
+               msg("this dump volume will be rewritten.\n");
+               killall();
+               nogripe = 1;
+               close_rewind();
+               Exit(X_REWRITE);
+       }
+       if (query("Do you want to start the next tape?"))
+               return;
+       dumpabort(0);
+}
+
+static void
+sigpipe(UNUSED(int signo))
+{
+
+       quit("Broken pipe\n");
+}
+
+/*
+ * do_stats --
+ *     Update xferrate stats
+ */
+time_t
+do_stats(void)
+{
+       time_t tnow, ttaken;
+       int blocks;
+
+       tnow = time(NULL);
+       ttaken = tnow - tstart_volume;
+       blocks = spcl.c_tapea - tapea_volume;
+       msg("Volume %d completed at: %s", tapeno, ctime(&tnow));
+       if (! compressed)
+               msg("Volume %d %ld blocks (%.2fMB)\n", tapeno, 
+                       blocks, ((double)blocks * TP_BSIZE / 1048576));
+       if (ttaken > 0) {
+               long volkb = (bytes_written - tapea_bytes) / 1024;
+               long txfrate = volkb / ttaken;
+               msg("Volume %d took %d:%02d:%02d\n", tapeno,
+                       ttaken / 3600, (ttaken % 3600) / 60, ttaken % 60);
+               msg("Volume %d transfer rate: %ld kB/s\n", tapeno,
+                       txfrate);
+               xferrate += txfrate;
+               if (compressed) {
+                       double rate = .0005 + (double) blocks / (double) volkb;
+                       msg("Volume %d %ldkB uncompressed, %ldkB compressed,"
+                               " %1.3f:1\n",
+                               tapeno, blocks, volkb, rate);
+               }
+       }
+       return(tnow);
+}
+
+char *
+mktimeest(time_t tnow)
+{
+       static char msgbuf[128];
+       time_t deltat;
+
+       msgbuf[0] = '\0';
+
+       if (blockswritten < 500)
+               return NULL;
+       if (blockswritten > tapesize)
+               tapesize = blockswritten;
+       deltat = tstart_writing - tnow + (1.0 * (tnow - tstart_writing))
+               / blockswritten * tapesize;
+       if (tnow > tstart_volume)
+               (void)snprintf(msgbuf, sizeof(msgbuf),
+                       "%3.2f%% done at %ld kB/s, finished in %d:%02d\n",
+                       (blockswritten * 100.0) / tapesize,
+                       (spcl.c_tapea - tapea_volume) / (tnow - tstart_volume),
+                       (int)(deltat / 3600), (int)((deltat % 3600) / 60));
+       else
+               (void)snprintf(msgbuf, sizeof(msgbuf),
+                       "%3.2f%% done, finished in %d:%02d\n",
+                       (blockswritten * 100.0) / tapesize,
+                       (int)(deltat / 3600), (int)((deltat % 3600) / 60));
+
+       return msgbuf;
+}
+
+#if defined(SIGINFO)
+/*
+ * statussig --
+ *     information message upon receipt of SIGINFO
+ */
+void
+statussig(int notused)
+{
+       int save_errno = errno;
+       char *buf;
+
+       buf = mktimeest(time(NULL));
+       if (buf)
+               write(STDERR_FILENO, buf, strlen(buf));
+       errno = save_errno;
+}
+#endif
+
+static void
+flushtape(void)
+{
+       int i, blks, got;
+       long lastfirstrec;
+       struct slave_results returned;
+
+       int siz = (char *)nextblock - (char *)slp->req;
+
+       slp->req[trecno].count = 0;                     /* Sentinel */
+
+       if (dump_atomic_write( slp->fd, (char *)slp->req, siz) != siz)
+               quit("error writing command pipe: %s\n", strerror(errno));
+       slp->sent = 1; /* we sent a request, read the response later */
+
+       lastfirstrec = slp->firstrec;
+
+       if (++slp >= &slaves[SLAVES])
+               slp = &slaves[0];
+
+       /* Read results back from next slave */
+       if (slp->sent) {
+               if (dump_atomic_read( slp->fd, (char *)&returned, sizeof returned)
+                   != sizeof returned) {
+                       perror("  DUMP: error reading command pipe in master");
+                       dumpabort(0);
+               }
+               got = returned.unclen;
+               bytes_written += returned.clen;
+               if (returned.unclen == returned.clen)
+                       uncomprblks++;
+               slp->sent = 0;
+
+               /* Check for errors or end of tape */
+               if (got <= 0) {
+                       /* Check for errors */
+                       if (got < 0)
+                               tperror(-got);
+                       else
+                               msg("End of tape detected\n");
+
+                       /*
+                        * Drain the results, don't care what the values were.
+                        * If we read them here then trewind won't...
+                        */
+                       for (i = 0; i < SLAVES; i++) {
+                               if (slaves[i].sent) {
+                                       if (dump_atomic_read( slaves[i].fd,
+                                           (char *)&returned, sizeof returned)
+                                           != sizeof returned) {
+                                               perror("  DUMP: error reading command pipe in master");
+                                               dumpabort(0);
+                                       }
+                                       slaves[i].sent = 0;
+                               }
+                       }
+
+                       close_rewind();
+                       rollforward();
+                       return;
+               }
+       }
+
+       blks = 0;
+       if (spcl.c_type != TS_END) {
+               for (i = 0; i < spcl.c_count; i++)
+                       if (spcl.c_addr[i] != 0)
+                               blks++;
+       }
+       slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
+       slp->tapea = spcl.c_tapea;
+       slp->firstrec = lastfirstrec + ntrec;
+       slp->inode = curino;
+       nextblock = slp->tblock;
+       trecno = 0;
+       asize += tenths + returned.clen / density;
+       blockswritten += ntrec;
+       blocksthisvol += ntrec;
+       if (!pipeout && !unlimited) {
+               if (blocksperfiles && blocksperfiles[blocksperfiles_current]) {
+                       if ( compressed ? (bytes_written - tapea_bytes + SLAVES * (writesize + sizeof(struct tapebuf))) >= (((long long)blocksperfiles[blocksperfiles_current]) * 1024)
+                                       : blocksthisvol >= blocksperfiles[blocksperfiles_current] ) {
+                               close_rewind();
+                               startnewtape(0);
+                       }
+               }
+               else if (asize > tsize) {
+                       close_rewind();
+                       startnewtape(0);
+               }
+       }
+       timeest();
+}
+
+time_t
+trewind(void)
+{
+       int f;
+       int got;
+       struct slave_results returned;
+
+       for (f = 0; f < SLAVES; f++) {
+               /*
+                * Drain the results, but unlike EOT we DO (or should) care
+                * what the return values were, since if we detect EOT after
+                * we think we've written the last blocks to the tape anyway,
+                * we have to replay those blocks with rollforward.
+                *
+                * fixme: punt for now.
+                */
+               if (slaves[f].sent) {
+                       if (dump_atomic_read( slaves[f].fd, (char *)&returned, sizeof returned)
+                           != sizeof returned) {
+                               perror("  DUMP: error reading command pipe in master");
+                               dumpabort(0);
+                       }
+                       got = returned.unclen;
+                       bytes_written += returned.clen;
+                       if (returned.unclen == returned.clen)
+                               uncomprblks++;
+                       slaves[f].sent = 0;
+
+                       if (got < 0)
+                               tperror(-got);
+
+                       if (got == 0) {
+                               msg("EOT detected in last 2 tape records!\n");
+                               msg("Use a longer tape, decrease the size estimate\n");
+                               quit("or use no size estimate at all.\n");
+                       }
+               }
+               (void) close(slaves[f].fd);
+       }
+       while (wait((int *)NULL) >= 0)  /* wait for any signals from slaves */
+               /* void */;
+
+       if (!pipeout) {
+
+               msg("Closing %s\n", tape);
+
+#ifdef RDUMP
+               if (host) {
+                       rmtclose();
+                       while (rmtopen(tape, O_RDONLY) < 0)
+                               sleep(10);
+                       rmtclose();
+               }
+               else 
+#endif
+               {
+                       (void) close(tapefd);
+                       if (!fifoout) {
+                               while ((f = OPEN(tape, O_RDONLY)) < 0)
+                                       sleep (10);
+                               (void) close(f);
+                       }
+               }
+       }
+       return do_stats();
+}
+
+               
+void
+close_rewind(void)
+{
+       int eot_code = 1;
+       (void)trewind();
+       if (eot_script) {
+               msg("Launching %s\n", eot_script);
+               eot_code = system_command(eot_script, tape, tapeno);
+       }
+       if (eot_code != 0 && eot_code != 1) {
+               msg("Dump aborted by the end of tape script\n");
+               dumpabort(0);
+       }
+       if (eot_code == 0)
+               return;
+       if (nexttape || Mflag)
+               return;
+       if (!nogripe) {
+               msg("Change Volumes: Mount volume #%d\n", tapeno+1);
+               broadcast("CHANGE DUMP VOLUMES!\7\7\n");
+       }
+       while (!query("Is the new volume mounted and ready to go?"))
+               if (query("Do you want to abort?")) {
+                       dumpabort(0);
+                       /*NOTREACHED*/
+               }
+}
+
+void
+rollforward(void)
+{
+       struct req *p, *q = NULL, *prev;
+       struct slave *tslp;
+       int i, size, savedtapea, got;
+       union u_spcl *ntb, *otb;
+       struct slave_results returned;
+#ifdef __linux__
+       int blks;
+       long lastfirstrec;
+#endif
+       tslp = &slaves[SLAVES];
+       ntb = (union u_spcl *)tslp->tblock[1];
+
+       /*
+        * Each of the N slaves should have requests that need to
+        * be replayed on the next tape.  Use the extra slave buffers
+        * (slaves[SLAVES]) to construct request lists to be sent to
+        * each slave in turn.
+        */
+       for (i = 0; i < SLAVES; i++) {
+               q = &tslp->req[1];
+               otb = (union u_spcl *)slp->tblock;
+
+               /*
+                * For each request in the current slave, copy it to tslp.
+                */
+
+               prev = NULL;
+               for (p = slp->req; p->count > 0; p += p->count) {
+                       *q = *p;
+                       if (p->dblk == 0)
+                               *ntb++ = *otb++; /* copy the datablock also */
+                       prev = q;
+                       q += q->count;
+               }
+               if (prev == NULL)
+                       quit("rollforward: protocol botch");
+               if (prev->dblk != 0)
+                       prev->count -= 1;
+               else
+                       ntb--;
+               q -= 1;
+               q->count = 0;
+               q = &tslp->req[0];
+               if (i == 0) {
+                       q->dblk = 0;
+                       q->count = 1;
+                       trecno = 0;
+                       nextblock = tslp->tblock;
+                       savedtapea = spcl.c_tapea;
+                       spcl.c_tapea = slp->tapea;
+                       startnewtape(0);
+                       spcl.c_tapea = savedtapea;
+                       lastspclrec = savedtapea - 1;
+               }
+               size = (char *)ntb - (char *)q;
+               if (dump_atomic_write( slp->fd, (char *)q, size) != size) {
+                       perror("  DUMP: error writing command pipe");
+                       dumpabort(0);
+               }
+               slp->sent = 1;
+#ifdef __linux__
+               lastfirstrec = slp->firstrec;
+#endif
+               if (++slp >= &slaves[SLAVES])
+                       slp = &slaves[0];
+
+               q->count = 1;
+
+               if (prev->dblk != 0) {
+                       /*
+                        * If the last one was a disk block, make the
+                        * first of this one be the last bit of that disk
+                        * block...
+                        */
+                       q->dblk = prev->dblk +
+                               prev->count * (TP_BSIZE / DEV_BSIZE);
+                       ntb = (union u_spcl *)tslp->tblock;
+               } else {
+                       /*
+                        * It wasn't a disk block.  Copy the data to its
+                        * new location in the buffer.
+                        */
+                       q->dblk = 0;
+                       *((union u_spcl *)tslp->tblock) = *ntb;
+                       ntb = (union u_spcl *)tslp->tblock[1];
+               }
+       }
+       slp->req[0] = *q;
+       nextblock = slp->tblock;
+       if (q->dblk == 0) {
+#ifdef __linux__
+       /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
+               *(union u_spcl *)(*nextblock) = *(union u_spcl *)tslp->tblock;
+#endif
+               nextblock++;
+       }
+       trecno = 1;
+
+       /*
+        * Clear the first slaves' response.  One hopes that it
+        * worked ok, otherwise the tape is much too short!
+        */
+       if (slp->sent) {
+               if (dump_atomic_read( slp->fd, (char *)&returned, sizeof returned)
+                   != sizeof returned) {
+                       perror("  DUMP: error reading command pipe in master");
+                       dumpabort(0);
+               }
+               got = returned.unclen;
+               bytes_written += returned.clen;
+               if (returned.clen == returned.unclen)
+                       uncomprblks++;
+               slp->sent = 0;
+
+               if (got < 0)
+                       tperror(-got);
+
+               if (got == 0) {
+                       quit("EOT detected at start of the tape!\n");
+               }
+       }
+
+#ifdef __linux__
+       blks = 0;
+       if (spcl.c_type != TS_END) {
+               for (i = 0; i < spcl.c_count; i++)
+                       if (spcl.c_addr[i] != 0)
+                               blks++;
+       }
+
+       slp->firstrec = lastfirstrec + ntrec;
+       slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
+       slp->inode = curino;
+       asize += tenths + returned.clen / density;
+       blockswritten += ntrec;
+       blocksthisvol += ntrec;
+#endif
+}
+
+/*
+ * We implement taking and restoring checkpoints on the tape level.
+ * When each tape is opened, a new process is created by forking; this
+ * saves all of the necessary context in the parent.  The child
+ * continues the dump; the parent waits around, saving the context.
+ * If the child returns X_REWRITE, then it had problems writing that tape;
+ * this causes the parent to fork again, duplicating the context, and
+ * everything continues as if nothing had happened.
+ */
+void
+startnewtape(int top)
+{
+       int     parentpid;
+       int     childpid;
+       int     status;
+       int     waitpid;
+       char    *p;
+
+#ifdef __linux__
+       sigset_t sigs;
+       sigemptyset(&sigs);
+       sigaddset(&sigs, SIGINT);
+       sigprocmask(SIG_BLOCK, &sigs, NULL);
+#else  /* __linux__ */
+#ifdef sunos
+       void    (*interrupt_save)();
+#else
+       sig_t   interrupt_save;
+#endif
+       interrupt_save = signal(SIGINT, SIG_IGN);
+#endif /* __linux__ */
+
+       parentpid = getpid();
+       tapea_volume = spcl.c_tapea;
+       tapea_bytes = bytes_written;
+       tstart_volume = time(NULL);
+
+restore_check_point:
+#ifdef __linux__
+       sigprocmask(SIG_UNBLOCK, &sigs, NULL);
+#else
+       (void)signal(SIGINT, interrupt_save);
+#endif
+       /*
+        *      All signals are inherited...
+        */
+       childpid = fork();
+       if (childpid < 0) {
+               msg("Context save fork fails in parent %d\n", parentpid);
+               Exit(X_ABORT);
+       }
+       if (childpid != 0) {
+               /*
+                *      PARENT:
+                *      save the context by waiting
+                *      until the child doing all of the work returns.
+                *      don't catch the interrupt
+                */
+#ifdef __linux__
+               sigprocmask(SIG_BLOCK, &sigs, NULL);
+#else
+               signal(SIGINT, SIG_IGN);
+#endif
+#ifdef TDEBUG
+               msg("Tape: %d; parent process: %d child process %d\n",
+                       tapeno+1, parentpid, childpid);
+#endif /* TDEBUG */
+               while ((waitpid = wait(&status)) != childpid)
+                       if (waitpid != rshpid)
+                               msg("Parent %d waiting for child %d has another child %d return\n",
+                               parentpid, childpid, waitpid);
+               if (status & 0xFF) {
+                       msg("Child %d returns LOB status %o\n",
+                               childpid, status&0xFF);
+               }
+               status = (status >> 8) & 0xFF;
+#ifdef TDEBUG
+               switch(status) {
+                       case X_FINOK:
+                               msg("Child %d finishes X_FINOK\n", childpid);
+                               break;
+                       case X_ABORT:
+                               msg("Child %d finishes X_ABORT\n", childpid);
+                               break;
+                       case X_REWRITE:
+                               msg("Child %d finishes X_REWRITE\n", childpid);
+                               break;
+                       default:
+                               msg("Child %d finishes unknown %d\n",
+                                       childpid, status);
+                               break;
+               }
+#endif /* TDEBUG */
+               switch(status) {
+                       case X_FINOK:
+                               Exit(X_FINOK);
+                       case X_ABORT:
+                               Exit(X_ABORT);
+                       case X_REWRITE:
+                               goto restore_check_point;
+                       default:
+                               msg("Bad return code from dump: %d\n", status);
+                               Exit(X_ABORT);
+               }
+               /*NOTREACHED*/
+       } else {        /* we are the child; just continue */
+#ifdef TDEBUG
+               sleep(4);       /* allow time for parent's message to get out */
+               msg("Child on Tape %d has parent %d, my pid = %d\n",
+                       tapeno+1, parentpid, getpid());
+#endif /* TDEBUG */
+               /*
+                * If we have a name like "/dev/rmt0,/dev/rmt1",
+                * use the name before the comma first, and save
+                * the remaining names for subsequent volumes.
+                */
+               tapeno++;               /* current tape sequence */
+               if (Mflag) {
+                       snprintf(tape, MAXPATHLEN, "%s%03d", tapeprefix, tapeno);
+                       tape[MAXPATHLEN - 1] = '\0';
+                       msg("Dumping volume %d on %s\n", tapeno, tape);
+               }
+               else if (nexttape || strchr(tapeprefix, ',')) {
+                       if (nexttape && *nexttape)
+                               tapeprefix = nexttape;
+                       if ((p = strchr(tapeprefix, ',')) != NULL) {
+                               *p = '\0';
+                               nexttape = p + 1;
+                       } else
+                               nexttape = NULL;
+                       strncpy(tape, tapeprefix, MAXPATHLEN);
+                       tape[MAXPATHLEN - 1] = '\0';
+                       msg("Dumping volume %d on %s\n", tapeno, tape);
+               }
+               if (blocksperfiles && blocksperfiles_current < *blocksperfiles)
+                       blocksperfiles_current++;
+#ifdef RDUMP
+               while ((tapefd = (host ? rmtopen(tape, O_WRONLY|O_CREAT|O_TRUNC) : pipeout ? 
+                       fileno(stdout) : 
+                       OPEN(tape, O_WRONLY|O_CREAT|O_TRUNC, 0666))) < 0)
+#else
+               while ((tapefd = (pipeout ? fileno(stdout) :
+                                 OPEN(tape, O_WRONLY|O_CREAT|O_TRUNC, 0666))) < 0)
+#endif
+                   {
+                       msg("Cannot open output \"%s\": %s\n", tape, 
+                           strerror(errno));
+                       if (!query("Do you want to retry the open?"))
+                               dumpabort(0);
+               }
+#ifdef RDUMP
+               if (!host)
+#endif
+                       {
+                               struct mtget mt_stat;
+                               magtapeout = ioctl(tapefd, MTIOCGET, (char *)&mt_stat) == 0;
+                               /*
+                               msg("Output is to %s\n", 
+                                       magtapeout ? "tape" : "file/pipe");
+                               */
+                       }
+
+               enslave();  /* Share open tape file descriptor with slaves */
+
+               asize = 0;
+               blocksthisvol = 0;
+               if (top)
+                       newtape++;              /* new tape signal */
+               spcl.c_count = slp->count;
+               /*
+                * measure firstrec in TP_BSIZE units since restore doesn't
+                * know the correct ntrec value...
+                */
+               spcl.c_firstrec = slp->firstrec;
+               spcl.c_volume++;
+               spcl.c_type = TS_TAPE;
+               spcl.c_flags |= DR_NEWHEADER;
+               spcl.c_ntrec = ntrec;
+               if (compressed)
+                       spcl.c_flags |= DR_COMPRESSED;
+               writeheader((dump_ino_t)slp->inode);
+               spcl.c_flags &=~ DR_NEWHEADER;
+               msg("Volume %d started with block %ld at: %s", tapeno, 
+                   spcl.c_tapea, ctime(&tstart_volume));
+               if (tapeno > 1)
+                       msg("Volume %d begins with blocks from inode %d\n",
+                               tapeno, slp->inode);
+               if (tapeno < (int)TP_NINOS)
+                       volinfo[tapeno] = slp->inode;
+       }
+}
+
+void
+dumpabort(UNUSED(int signo))
+{
+
+       if (master != 0 && master != getpid())
+               /* Signals master to call dumpabort */
+               (void) kill(master, SIGTERM);
+       else {
+               killall();
+               msg("The ENTIRE dump is aborted.\n");
+       }
+#ifdef RDUMP
+       rmtclose();
+#endif
+       Exit(X_ABORT);
+}
+
+void
+Exit(int status)
+{
+
+#ifdef TDEBUG
+       msg("pid = %d exits with status %d\n", getpid(), status);
+#endif /* TDEBUG */
+       exit(status);
+}
+
+/*
+ * proceed - handler for SIGUSR2, used to synchronize IO between the slaves.
+ */
+static void
+proceed(UNUSED(int signo))
+{
+       if (ready)
+               siglongjmp(jmpbuf, 1);
+       caught++;
+}
+
+void
+enslave(void)
+{
+       int cmd[2];
+#ifdef LINUX_FORK_BUG
+       int i, j;
+#else
+       int i, j;
+#endif
+
+       master = getpid();
+
+    {  struct sigaction sa;
+       memset(&sa, 0, sizeof sa);
+       sigemptyset(&sa.sa_mask);
+       sa.sa_handler = dumpabort;
+       sigaction(SIGTERM, &sa, NULL); /* Slave sends SIGTERM on dumpabort() */
+       sa.sa_handler = sigpipe;
+       sigaction(SIGPIPE, &sa, NULL);
+       sa.sa_handler = proceed;
+       sa.sa_flags = SA_RESTART;
+       sigaction(SIGUSR2, &sa, NULL); /* Slave sends SIGUSR2 to next slave */
+   }
+
+       for (i = 0; i < SLAVES; i++) {
+               if (i == slp - &slaves[0]) {
+                       caught = 1;
+               } else {
+                       caught = 0;
+               }
+
+               if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 ||
+                   (slaves[i].pid = fork()) < 0)
+                       quit("too many slaves, %d (recompile smaller): %s\n",
+                           i, strerror(errno));
+
+               slaves[i].fd = cmd[1];
+               slaves[i].sent = 0;
+               if (slaves[i].pid == 0) {           /* Slave starts up here */
+                       sigset_t sigs;
+                       for (j = 0; j <= i; j++)
+                               (void) close(slaves[j].fd);
+                       sigemptyset(&sigs);
+                       sigaddset(&sigs, SIGINT);  /* Master handles this */
+#if defined(SIGINFO)
+                       sigaddset(&sigs, SIGINFO);
+#endif
+                       sigprocmask(SIG_BLOCK, &sigs, NULL);
+
+#ifdef LINUX_FORK_BUG
+                       if (dump_atomic_write( cmd[0], (char *) &i, sizeof i)
+                           != sizeof i)
+                               quit("master/slave protocol botched 3\n");
+#endif
+                       doslave(cmd[0], 
+#ifdef WRITEDEBUG
+                               i, 
+#endif
+                               (slaves[i].pid == slp->pid));
+                       Exit(X_FINOK);
+               }
+               else
+                       close(cmd[0]);
+       }
+
+#ifdef LINUX_FORK_BUG
+       /*
+        * Wait for all slaves to _actually_ start to circumvent a bug in
+        * Linux kernels >= 2.1.3 where a signal sent to a child that hasn't
+        * returned from fork() causes a SEGV in the child process
+        */
+       for (i = 0; i < SLAVES; i++)
+               if (dump_atomic_read( slaves[i].fd, (char *) &j, sizeof j) != sizeof j)
+                       quit("master/slave protocol botched 4\n");
+#endif
+
+       for (i = 0; i < SLAVES; i++)
+               (void) dump_atomic_write( slaves[i].fd, 
+                             (char *) &slaves[(i + 1) % SLAVES].pid, 
+                             sizeof slaves[0].pid);
+               
+       master = 0; 
+}
+
+void
+killall(void)
+{
+       int i;
+
+       for (i = 0; i < SLAVES; i++)
+               if (slaves[i].pid > 0) {
+                       (void) kill(slaves[i].pid, SIGKILL);
+                       slaves[i].sent = 0;
+               }
+}
+
+/*
+ * Synchronization - each process waits for a SIGUSR2 from the
+ * previous process before writing to the tape, and sends SIGUSR2
+ * to the next process when the tape write completes. On tape errors
+ * a SIGUSR1 is sent to the master which then terminates all of the
+ * slaves.
+ */
+static void
+doslave(int cmd, 
+#ifdef WRITEDEBUG
+       int slave_number, 
+#endif
+       int first)
+{
+       int nread;
+       int nextslave;
+       volatile int wrote = 0, size, eot_count, bufsize;
+       char * volatile buffer;
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+       struct tapebuf * volatile comp_buf = NULL;
+       int compresult;
+       volatile int do_compress = !first;
+       unsigned long worklen;
+#ifdef HAVE_LZO
+       lzo_align_t __LZO_MMODEL *LZO_WorkMem;
+#endif
+#endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
+       struct slave_results returns;
+#ifdef __linux__
+       errcode_t retval;
+#endif
+#ifdef USE_QFA
+       long long curtapepos;
+       union u_spcl *uspclptr;
+       struct s_spcl *spclptr;
+       /* long         maxntrecs = 300000000 / (ntrec * 1024);  last tested: 50 000 000 */
+       long            maxntrecs = 50000;      /* every 50MB */
+       long            cntntrecs = maxntrecs;
+#endif /* USE_QFA */
+       sigset_t set;
+
+       sigemptyset(&set);
+       sigaddset(&set, SIGUSR2);
+       sigprocmask(SIG_BLOCK, &set, NULL);
+       sigemptyset(&set);
+
+       /*
+        * Need our own seek pointer.
+        */
+       (void) close(diskfd);
+       if ((diskfd = OPEN(disk, O_RDONLY)) < 0)
+               quit("slave couldn't reopen disk: %s\n", strerror(errno));
+#ifdef __linux__
+#ifdef BLKFLSBUF
+       (void)ioctl(diskfd, BLKFLSBUF, 0);
+#endif
+       ext2fs_close(fs);
+       retval = dump_fs_open(disk, &fs);
+       if (retval)
+               quit("slave couldn't reopen disk: %s\n", error_message(retval));
+#endif /* __linux__ */
+
+       /*
+        * Need the pid of the next slave in the loop...
+        */
+       if ((nread = dump_atomic_read( cmd, (char *)&nextslave, sizeof nextslave))
+           != sizeof nextslave) {
+               quit("master/slave protocol botched - didn't get pid of next slave.\n");
+       }
+
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+       /* if we're doing a compressed dump, allocate the compress buffer */
+       if (compressed) {
+               int bsiz = sizeof(struct tapebuf) + writesize;
+               /* Add extra space to deal with compression enlarging the buffer */
+               if (TP_BSIZE > writesize/16 + 67)
+                       bsiz += TP_BSIZE;
+               else
+                       bsiz += writesize/16 + 67;
+               comp_buf = malloc(bsiz);
+               if (comp_buf == NULL)
+                       quit("couldn't allocate a compress buffer.\n");
+               if (zipflag == COMPRESS_ZLIB)
+                       comp_buf->flags = COMPRESS_ZLIB;
+               else if (zipflag == COMPRESS_BZLIB)
+                       comp_buf->flags = COMPRESS_BZLIB;
+                else if (zipflag == COMPRESS_LZO) {
+                       comp_buf->flags = COMPRESS_LZO;
+                       if (lzo_init() != LZO_E_OK) quit("lzo_init failed\n");
+                } else 
+                       quit("internal error - unknown compression method: %d\n", zipflag);
+       }
+#ifdef HAVE_LZO
+       LZO_WorkMem = malloc(LZO1X_1_MEM_COMPRESS);
+       if (!LZO_WorkMem)
+               quit("couldn't allocate a compress buffer.\n");
+#endif
+#endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
+
+       /*
+        * Get list of blocks to dump, read the blocks into tape buffer
+        */
+       while ((nread = dump_atomic_read( cmd, (char *)slp->req, reqsiz)) == reqsiz) {
+               struct req *p = slp->req;
+
+               for (trecno = 0; trecno < ntrec;
+                    trecno += p->count, p += p->count) {
+                       if (p->dblk) {  /* read a disk block */
+                               bread(p->dblk, slp->tblock[trecno],
+                                       p->count * TP_BSIZE);
+                       } else {        /* read record from pipe */
+                               if (p->count != 1 || dump_atomic_read( cmd,
+                                   (char *)slp->tblock[trecno],
+                                   TP_BSIZE) != TP_BSIZE)
+                                      quit("master/slave protocol botched.\n");
+                       }
+               }
+
+               /* Try to write the data... */
+               wrote = 0;
+               eot_count = 0;
+               size = 0;
+               buffer = (char *) slp->tblock[0];       /* set write pointer */
+               bufsize = writesize;                    /* length to write */
+               returns.clen = returns.unclen = bufsize;
+
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+               /* 
+                * When writing a compressed dump, each block except
+                * the first one on each tape is written
+                * from struct tapebuf with an 4 byte prefix
+                * followed by the data. This can be less than
+                * writesize. Restore, on a short read, can compare the
+                * length read to the compressed length in the header
+                * to verify that the read was good. Blocks which don't
+                * compress well are written uncompressed.
+                * The first block written by each slave is not compressed
+                * and does not have a prefix.
+                */
+
+               if (compressed && do_compress) {
+                       comp_buf->length = bufsize;
+                       worklen = TP_BSIZE + writesize;
+                       compresult = 1;
+#ifdef HAVE_ZLIB
+                       if (zipflag == COMPRESS_ZLIB) {
+                               compresult = compress2(comp_buf->buf, 
+                                                      &worklen,
+                                                      (char *)slp->tblock[0],
+                                                      writesize, 
+                                                      compressed);
+                               if (compresult == Z_OK)
+                                       compresult = 1;
+                               else
+                                       compresult = 0;
+                       }
+#endif /* HAVE_ZLIB */
+#ifdef HAVE_BZLIB
+                       if (zipflag == COMPRESS_BZLIB) {
+                               unsigned int worklen2 = worklen;
+                               compresult = BZ2_bzBuffToBuffCompress(
+                                                      comp_buf->buf,
+                                                      &worklen2,
+                                                      (char *)slp->tblock[0],
+                                                      writesize,
+                                                      compressed,
+                                                      0, 30);
+                               worklen = worklen2;
+                               if (compresult == BZ_OK)
+                                       compresult = 1;
+                               else
+                                       compresult = 0;
+                       }
+
+#endif /* HAVE_BZLIB */
+#ifdef HAVE_LZO
+                       if (zipflag == COMPRESS_LZO) {
+                               lzo_uint worklen2 = worklen;
+                               compresult = lzo1x_1_compress((char *)slp->tblock[0],writesize,
+                                                              comp_buf->buf,
+                                                             &worklen2,
+                                                              LZO_WorkMem);
+                               worklen = worklen2;
+                               if (compresult == LZO_E_OK)
+                                       compresult = 1;
+                               else
+                                       compresult = 0;
+                       }
+#endif /* HAVE_LZO */
+                       if (compresult && worklen <= ((unsigned long)writesize - 16)) {
+                               /* write the compressed buffer */
+                               comp_buf->length = worklen;
+                               comp_buf->compressed = 1;
+                               buffer = (char *) comp_buf;
+                               returns.clen = bufsize = worklen + sizeof(struct tapebuf);
+                       }
+                       else {
+                               /* write the data uncompressed */
+                               comp_buf->length = writesize;
+                               comp_buf->compressed = 0;
+                               buffer = (char *) comp_buf;
+                               returns.clen = bufsize = writesize + sizeof(struct tapebuf);
+                               returns.unclen = returns.clen;
+                               memcpy(comp_buf->buf, (char *)slp->tblock[0], writesize);
+                       }
+               }
+               /* compress the remaining blocks if we're compressing */
+               do_compress = compressed;
+#endif /* HAVE_ZLIB  || HAVE_BZLIB || HAVE_LZO */
+
+               if (sigsetjmp(jmpbuf, 1) == 0) {
+                       ready = 1;
+                       if (!caught)
+                               sigsuspend(&set);
+               }
+               ready = 0;
+               caught = 0;
+
+#ifdef USE_QFA
+               if (gTapeposfd >= 0) {
+                       int i;
+                       int foundone = 0;
+
+                       for (i = 0; (i < ntrec) && !foundone; ++i) {
+                               uspclptr = (union u_spcl *)&slp->tblock[i];
+                               spclptr = &uspclptr->s_spcl;
+                               if ((spclptr->c_magic == NFS_MAGIC) && 
+                                                       (spclptr->c_type == TS_INODE) &&
+                                                       (spclptr->c_date == gThisDumpDate) &&
+                                                       !(spclptr->c_dinode.di_mode & S_IFDIR)
+                                               ) {
+                                       foundone = 1;
+                                       /* if (cntntrecs >= maxntrecs) {         only write every maxntrecs amount of data */
+                                               cntntrecs = 0;
+                                               if (gtperr == 0) 
+                                                       gtperr = GetTapePos(&curtapepos);
+                                               /* if an error occured previously don't
+                                                * try again */
+                                               if (gtperr == 0) {
+#ifdef DEBUG_QFA
+                                                       msg("inode %ld at tapepos %ld\n", spclptr->c_inumber, curtapepos);
+#endif
+                                                       gtperr = MkTapeString(spclptr, curtapepos);
+                                               }
+                                       /* } */
+                               }
+                       }
+               }
+#endif /* USE_QFA */
+                                               
+               while (eot_count < 10 && size < bufsize) {
+#ifdef RDUMP
+                       if (host)
+                               wrote = rmtwrite(buffer + size, bufsize - size);
+                       else
+#endif
+                               wrote = write(tapefd, buffer + size, bufsize - size);
+#ifdef WRITEDEBUG
+                       printf("slave %d wrote %d\n", slave_number, wrote);
+#endif
+                       if (wrote < 0 && errno != ENOSPC)
+                               break;
+                       if (wrote == 0 || (wrote < 0 && errno == ENOSPC))
+                               eot_count++;
+                       else
+                               size += wrote;
+               }
+
+#ifdef WRITEDEBUG
+               if (size != bufsize)
+                printf("slave %d only wrote %d out of %d bytes and gave up.\n",
+                    slave_number, size, bufsize);
+#endif
+
+               /*
+                * Handle ENOSPC as an EOT condition.
+                */
+               if (wrote < 0 && errno == ENOSPC) {
+                       wrote = 0;
+                       eot_count++;
+               }
+
+               if (eot_count > 0)
+                       returns.clen = returns.unclen = 0;
+
+               /*
+                * pass errno back to master for special handling
+                */
+               if (wrote < 0)
+                       returns.unclen = -errno;
+
+               /*
+                * pass size of data and size of write back to master
+                * (for EOT handling)
+                */
+               (void) dump_atomic_write( cmd, (char *)&returns, sizeof returns);
+
+               /*
+                * Signal the next slave to go.
+                */
+               (void) kill(nextslave, SIGUSR2);
+#ifdef USE_QFA
+               if (gTapeposfd >= 0) {
+                       cntntrecs += ntrec;
+               }
+#endif /* USE_QFA */
+       }
+       if (nread != 0)
+               quit("error reading command pipe: %s\n", strerror(errno));
+}
+
+/*
+ * Since a read from a pipe may not return all we asked for,
+ * or a write may not write all we ask if we get a signal,
+ * loop until the count is satisfied (or error).
+ */
+static ssize_t
+dump_atomic_read(int fd, char *buf, size_t count)
+{
+       int got, need = count;
+
+       do {
+               while ((got = read(fd, buf, need)) > 0 && (need -= got) > 0)
+                       buf += got;
+       } while (got == -1 && errno == EINTR);
+       return (got < 0 ? got : (ssize_t)count - need);
+}
+
+/*
+ * Since a read from a pipe may not return all we asked for,
+ * or a write may not write all we ask if we get a signal,
+ * loop until the count is satisfied (or error).
+ */
+static ssize_t
+dump_atomic_write(int fd, const char *buf, size_t count)
+{
+       int got, need = count;
+
+       do {
+               while ((got = write(fd, buf, need)) > 0 && (need -= got) > 0)
+                       buf += got;
+       } while (got == -1 && errno == EINTR);
+       return (got < 0 ? got : (ssize_t)count - need);
+}
+
+
+/*
+int
+SetLogicalPos(void)
+{
+       int     err = 0;
+       struct mt_pos buf;
+
+       buf.mt_op = MTSETDRVBUFFER;
+       buf.mt_count = MT_ST_BOOLEANS | MT_ST_SCSI2LOGICAL;
+       if (ioctl(tapefd, MTIOCTOP, &buf) == -1) {
+               err = errno;
+               msg("[%ld] error: %d (setting logical)\n", 
+                       (unsigned long)getpid(), err);
+       }
+       return err;
+}
+*/
+
+#ifdef USE_QFA
+#define LSEEK_GET_TAPEPOS      10
+#define LSEEK_GO2_TAPEPOS      11
+/*
+ * read the current tape position
+ */
+static int
+GetTapePos(long long *pos)
+{
+       int err = 0;
+
+#ifdef RDUMP
+       if (host) {
+               *pos = (long long) rmtseek((OFF_T)0, (int)LSEEK_GET_TAPEPOS);
+               err = *pos < 0;
+       }
+       else 
+#endif
+       {
+       if (magtapeout) {
+               long mtpos;
+               *pos = 0;
+               err = (ioctl(tapefd, MTIOCPOS, &mtpos) < 0);
+               *pos = (long long)mtpos;
+       }
+       else {
+               *pos = LSEEK(tapefd, 0, SEEK_CUR);
+               err = (*pos < 0);
+       }
+       }
+       if (err) {
+               err = errno;
+               msg("[%ld] error: %d (getting tapepos: %lld)\n", getpid(), 
+                       err, *pos);
+               return err;
+       }
+       return err;
+}
+
+static int 
+MkTapeString(struct s_spcl *spclptr, long long curtapepos)
+{
+       int     err = 0;
+
+#ifdef DEBUG_QFA
+       msg("inode %ld at tapepos %lld\n", spclptr->c_inumber, curtapepos);
+#endif
+
+       snprintf(gTps, sizeof(gTps), "%ld\t%d\t%lld\n", 
+                (unsigned long)spclptr->c_inumber, 
+                tapeno, 
+                curtapepos);
+       gTps[sizeof(gTps) - 1] = '\0';
+       if (write(gTapeposfd, gTps, strlen(gTps)) != (ssize_t)strlen(gTps)) {
+               err = errno;
+       warn("error writing tapepos file. (error %d)\n", errno);
+       }
+       return err;
+}
+#endif /* USE_QFA */
diff --git a/dump/traverse.c b/dump/traverse.c
new file mode 100644 (file)
index 0000000..4104799
--- /dev/null
@@ -0,0 +1,1399 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1980, 1988, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: traverse.c,v 1.61 2004/07/01 09:14:49 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef __STDC__
+#include <string.h>
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef __linux__
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>
+#include <bsdcompat.h>
+#include <compaterr.h>
+#include <stdlib.h>
+#elif defined sunos
+#include <sys/vnode.h>
+
+#include <ufs/fs.h>
+#include <ufs/fsdir.h>
+#include <ufs/inode.h>
+#else
+#include <ufs/ufs/dir.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+#endif /* __linux__ */
+
+#include <protocols/dumprestore.h>
+
+#include "dump.h"
+
+#define        HASDUMPEDFILE   0x1
+#define        HASSUBDIRS      0x2
+
+#ifdef __linux__
+typedef u_quad_t fsizeT;
+#else
+#ifdef FS_44INODEFMT
+typedef        quad_t fsizeT;
+#else
+typedef        long fsizeT;
+#endif
+#endif
+
+#ifdef __linux__
+static int searchdir __P((struct ext2_dir_entry *dp, int offset,
+                          int blocksize, char *buf, void *private));
+#else
+static int dirindir __P((dump_ino_t ino, daddr_t blkno, int level, long *size));
+static void dmpindir __P((dump_ino_t ino, daddr_t blk, int level, fsizeT *size));
+static int searchdir __P((dump_ino_t ino, daddr_t blkno, long size, long filesize));
+#endif
+static void mapfileino __P((dump_ino_t ino, struct dinode const *dp, long *tapesize, int *dirskipped));
+
+#ifdef HAVE_EXT2_JOURNAL_INUM
+#define ext2_journal_ino(sb) (sb->s_journal_inum)
+#else
+#define ext2_journal_ino(sb) (*((u_int32_t *)sb + 0x38))
+#endif
+#ifndef HAVE_EXT2_INO_T
+typedef ino_t ext2_ino_t;
+#endif
+
+#ifndef EXT3_FEATURE_COMPAT_HAS_JOURNAL
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL                0x0004
+#endif
+#ifndef EXT2_FEATURE_INCOMPAT_FILETYPE
+#define EXT2_FEATURE_INCOMPAT_FILETYPE         0x0002
+#endif
+#ifndef EXT3_FEATURE_INCOMPAT_RECOVER
+#define EXT3_FEATURE_INCOMPAT_RECOVER          0x0004
+#endif
+#ifndef EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV      0x0008
+#endif
+
+#ifndef EXT2_LIB_FEATURE_INCOMPAT_SUPP
+#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_RECOVER | \
+                                       EXT2_FEATURE_INCOMPAT_FILETYPE)
+#endif
+#ifndef EXT2_RESIZE_INO
+#define EXT2_RESIZE_INO                        7
+#endif
+#ifndef EXT2_FT_UNKNOWN
+#define EXT2_FT_UNKNOWN                0
+#define EXT2_FT_REG_FILE       1
+#define EXT2_FT_DIR            2
+#define EXT2_FT_CHRDEV         3
+#define EXT2_FT_BLKDEV         4
+#define EXT2_FT_FIFO           5
+#define EXT2_FT_SOCK           6
+#define EXT2_FT_SYMLINK                7
+#define EXT2_FT_MAX            8
+#endif
+
+int dump_fs_open(const char *disk, ext2_filsys *fs)
+{
+       int retval;
+
+       retval = ext2fs_open(disk, EXT2_FLAG_FORCE, 0, 0, unix_io_manager, fs);
+       if (!retval) {
+               struct ext2_super_block *es = (*fs)->super;
+               dump_ino_t journal_ino = ext2_journal_ino(es);
+
+               if (es->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV){
+                       msg("This is a journal, not a filesystem!\n");
+                       retval = EXT2_ET_UNSUPP_FEATURE;
+                       ext2fs_close(*fs);
+               }
+               else if ((retval = es->s_feature_incompat &
+                                       ~(EXT2_LIB_FEATURE_INCOMPAT_SUPP |
+                                         EXT3_FEATURE_INCOMPAT_RECOVER))) {
+                       msg("Unsupported feature(s) 0x%x in filesystem\n",
+                               retval);
+                       retval = EXT2_ET_UNSUPP_FEATURE;
+                       ext2fs_close(*fs);
+               }
+               else {
+                       if (es->s_feature_compat &
+                               EXT3_FEATURE_COMPAT_HAS_JOURNAL && 
+                               journal_ino)
+                               do_exclude_ino(journal_ino, "journal inode");
+                       do_exclude_ino(EXT2_RESIZE_INO, "resize inode");
+               }
+       }
+       return retval;
+}
+
+/*
+ * This is an estimation of the number of TP_BSIZE blocks in the file.
+ * It estimates the number of blocks in files with holes by assuming
+ * that all of the blocks accounted for by di_blocks are data blocks
+ * (when some of the blocks are usually used for indirect pointers);
+ * hence the estimate may be high.
+ */
+long
+blockest(struct dinode const *dp)
+{
+       long blkest, sizeest;
+       u_quad_t i_size;
+
+       /*
+        * dp->di_size is the size of the file in bytes.
+        * dp->di_blocks stores the number of sectors actually in the file.
+        * If there are more sectors than the size would indicate, this just
+        *      means that there are indirect blocks in the file or unused
+        *      sectors in the last file block; we can safely ignore these
+        *      (blkest = sizeest below).
+        * If the file is bigger than the number of sectors would indicate,
+        *      then the file has holes in it.  In this case we must use the
+        *      block count to estimate the number of data blocks used, but
+        *      we use the actual size for estimating the number of indirect
+        *      dump blocks (sizeest vs. blkest in the indirect block
+        *      calculation).
+        */
+       blkest = howmany((u_quad_t)dp->di_blocks * 512, fs->blocksize) * (fs->blocksize / TP_BSIZE);
+       i_size = dp->di_size + ((u_quad_t) dp->di_size_high << 32);
+       sizeest = howmany(i_size, fs->blocksize) * (fs->blocksize / TP_BSIZE);
+       if (blkest > sizeest)
+               blkest = sizeest;
+#ifdef __linux__
+       if ((dp->di_mode & IFMT) == IFDIR) {
+               /*
+                * for directories, assume only half of space is filled
+                * with entries.  
+                */
+                blkest = blkest / 2;
+                sizeest = sizeest / 2;
+       }
+       if (i_size > (u_quad_t)fs->blocksize * NDADDR) {
+               /* calculate the number of indirect blocks on the dump tape */
+               blkest +=
+                       howmany(sizeest - NDADDR * fs->blocksize / TP_BSIZE,
+                       TP_NINDIR);
+       }
+#else
+       if (i_size > sblock->fs_bsize * NDADDR) {
+               /* calculate the number of indirect blocks on the dump tape */
+               blkest +=
+                       howmany(sizeest - NDADDR * sblock->fs_bsize / TP_BSIZE,
+                       TP_NINDIR);
+       }
+#endif
+       return (blkest + 1);
+}
+
+/* Auxiliary macro to pick up files changed since previous dump. */
+#define CSINCE(dp, t) \
+       ((dp)->di_ctime >= (t))
+#define MSINCE(dp, t) \
+       ((dp)->di_mtime >= (t))
+#define        CHANGEDSINCE(dp, t) \
+       (CSINCE(dp, t) || MSINCE(dp, t))
+
+/* The NODUMP_FLAG macro tests if a file has the nodump flag. */
+#ifdef UF_NODUMP
+#define NODUMP_FLAG(dp) (!nonodump && (((dp)->di_flags & UF_NODUMP) == UF_NODUMP))
+#else
+#define NODUMP_FLAG(dp) 0
+#endif
+
+/* The WANTTODUMP macro decides whether a file should be dumped. */
+#define        WANTTODUMP(dp, ino) \
+       (CHANGEDSINCE(dp, ((u_int32_t)spcl.c_ddate)) && \
+        (!NODUMP_FLAG(dp)) && \
+        (!exclude_ino(ino)))
+
+/*
+ * Determine if given inode should be dumped. "dp" must either point to a
+ * copy of the given inode, or be NULL (in which case it is fetched.)
+ */
+static void
+mapfileino(dump_ino_t ino, struct dinode const *dp, long *tapesize, int *dirskipped)
+{
+       int mode;
+
+       /*
+        * Skip inode if we've already marked it for dumping
+        */
+       if (TSTINO(ino, usedinomap))
+               return;
+       if (!dp)
+               dp = getino(ino);
+       if ((mode = (dp->di_mode & IFMT)) == 0)
+               return;
+#ifdef __linux__
+       if (dp->di_nlink == 0 || dp->di_dtime != 0)
+               return;
+#endif
+       /*
+        * Put all dirs in dumpdirmap, inodes that are to be dumped in the
+        * used map. All inode but dirs who have the nodump attribute go
+        * to the usedinomap.
+        */
+       SETINO(ino, usedinomap);
+
+       if (mode == IFDIR)
+               SETINO(ino, dumpdirmap);
+       if (WANTTODUMP(dp, ino)) {
+               SETINO(ino, dumpinomap);
+               if (!MSINCE(dp, (u_int32_t)spcl.c_ddate))
+                       SETINO(ino, metainomap);
+               if (mode != IFREG && mode != IFDIR && mode != IFLNK)
+                       *tapesize += 1;
+               else
+                       *tapesize += blockest(dp);
+               return;
+       }
+       if (mode == IFDIR) {
+               if ( NODUMP_FLAG(dp) || exclude_ino(ino) )
+                       CLRINO(ino, usedinomap);
+               *dirskipped = 1;
+       }
+}
+
+/*
+ * Dump pass 1.
+ *
+ * Walk the inode list for a filesystem to find all allocated inodes
+ * that have been modified since the previous dump time. Also, find all
+ * the directories in the filesystem.
+ */
+#ifdef __linux__
+int
+mapfiles(UNUSED(dump_ino_t maxino), long *tapesize)
+{
+       ext2_ino_t ino;
+       int anydirskipped = 0;
+       ext2_inode_scan scan;
+       errcode_t err;
+       struct ext2_inode inode;
+
+       /*
+        * We use libext2fs's inode scanning routines, which are particularly
+        * robust.  (Note that getino cannot return an error.)
+        */
+       err = ext2fs_open_inode_scan(fs, 0, &scan);
+       if (err) {
+               com_err(disk, err, "while opening inodes\n");
+               exit(X_ABORT);
+       }
+       for (;;) {
+               err = ext2fs_get_next_inode(scan, &ino, &inode);
+               if (err == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
+                       continue;
+               if (err) {
+                       com_err(disk, err, "while scanning inode #%ld\n",
+                               (long)ino);
+                       exit(X_ABORT);
+               }
+               if (ino == 0)
+                       break;
+
+               curino = ino;
+               mapfileino(ino, (struct dinode const *)&inode, tapesize,
+                          &anydirskipped);
+       }
+       ext2fs_close_inode_scan(scan);
+
+       /*
+        * Restore gets very upset if the root is not dumped,
+        * so ensure that it always is dumped.
+        */
+       SETINO(ROOTINO, dumpinomap);
+       return (anydirskipped);
+}
+#else
+int
+mapfiles(dump_ino_t maxino, long *tapesize)
+{
+       dump_ino_t ino;
+       int anydirskipped = 0;
+
+       for (ino = ROOTINO; ino < maxino; ino++)
+               mapfileino(ino, tapesize, &anydirskipped);
+
+       /*
+        * Restore gets very upset if the root is not dumped,
+        * so ensure that it always is dumped.
+        */
+       SETINO(ROOTINO, dumpinomap);
+       return (anydirskipped);
+}
+#endif /* __linux__ */
+
+#ifdef __linux__
+int
+maponefile(UNUSED(dump_ino_t maxino), long *tapesize, char *directory)
+{
+       errcode_t retval;
+       ext2_ino_t dir_ino;
+       char dir_name [MAXPATHLEN];
+       int i, anydirskipped = 0;
+
+       /*
+        * Mark every directory in the path as being dumped
+        */
+       for (i = 0; i < (int)strlen (directory); i++) {
+               if (directory[i] == '/') {
+                       strncpy (dir_name, directory, i);
+                       dir_name[i] = '\0';
+                       retval = ext2fs_namei(fs, ROOTINO, ROOTINO, 
+                                             dir_name, &dir_ino);
+                       if (retval) {
+                               com_err(disk, retval, 
+                                       "while translating %s", dir_name);
+                               exit(X_ABORT);
+                       }
+                       mapfileino((dump_ino_t) dir_ino, 0,
+                                  tapesize, &anydirskipped);
+               }
+       }
+       /*
+        * Mark the final directory
+        */
+       retval = ext2fs_namei(fs, ROOTINO, ROOTINO, directory, &dir_ino);
+       if (retval) {
+               com_err(disk, retval, "while translating %s", directory);
+               exit(X_ABORT);
+       }
+       mapfileino((dump_ino_t)dir_ino, 0, tapesize, &anydirskipped);
+
+       mapfileino(ROOTINO, 0, tapesize, &anydirskipped);
+
+       /*
+        * Restore gets very upset if the root is not dumped,
+        * so ensure that it always is dumped.
+        */
+       SETINO(ROOTINO, dumpdirmap);
+       return anydirskipped;
+}
+#endif /* __linux__ */
+
+#ifdef __linux__
+struct mapfile_context {
+       long *tapesize;
+       int *anydirskipped;
+};
+
+static int
+mapfilesindir(struct ext2_dir_entry *dirent, UNUSED(int offset), 
+             UNUSED(int blocksize), UNUSED(char *buf), void *private)
+{
+       struct dinode const *dp;
+       int mode;
+       errcode_t retval;
+       struct mapfile_context *mfc;
+       ext2_ino_t ino;
+
+       ino = dirent->inode;
+       mfc = (struct mapfile_context *)private;
+       dp = getino(dirent->inode);
+
+       mapfileino(dirent->inode, dp, mfc->tapesize, mfc->anydirskipped);
+
+       mode = dp->di_mode & IFMT;
+       if (mode == IFDIR && dp->di_nlink != 0 && dp->di_dtime == 0) {
+               if ((dirent->name[0] != '.' || ( dirent->name_len & 0xFF ) != 1) &&
+                   (dirent->name[0] != '.' || dirent->name[1] != '.' ||
+                    ( dirent->name_len & 0xFF ) != 2)) {
+               retval = ext2fs_dir_iterate(fs, ino, 0, NULL,
+                                           mapfilesindir, private);
+               if (retval)
+                       return retval;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Dump pass 1.
+ *
+ * Walk the inode list for a filesystem to find all allocated inodes
+ * that have been modified since the previous dump time. Also, find all
+ * the directories in the filesystem.
+ */
+int
+mapfilesfromdir(UNUSED(dump_ino_t maxino), long *tapesize, char *directory)
+{
+       errcode_t retval;
+       struct mapfile_context mfc;
+       ext2_ino_t dir_ino;
+       char dir_name [MAXPATHLEN];
+       int i, anydirskipped = 0;
+
+       /*
+        * Mark every directory in the path as being dumped
+        */
+       for (i = 0; i < (int)strlen (directory); i++) {
+               if (directory[i] == '/') {
+                       strncpy (dir_name, directory, i);
+                       dir_name[i] = '\0';
+                       retval = ext2fs_namei(fs, ROOTINO, ROOTINO, dir_name,
+                                             &dir_ino);
+                       if (retval) {
+                               com_err(disk, retval, "while translating %s",
+                                       dir_name);
+                               exit(X_ABORT);
+                       }
+                       mapfileino(dir_ino, 0, tapesize, &anydirskipped);
+               }
+       }
+       /*
+        * Mark the final directory
+        */
+       retval = ext2fs_namei(fs, ROOTINO, ROOTINO, directory, &dir_ino);
+       if (retval) {
+               com_err(disk, retval, "while translating %s", directory);
+               exit(X_ABORT);
+       }
+       mapfileino(dir_ino, 0, tapesize, &anydirskipped);
+
+       mfc.tapesize = tapesize;
+       mfc.anydirskipped = &anydirskipped;
+       retval = ext2fs_dir_iterate(fs, dir_ino, 0, NULL, mapfilesindir,
+                                   (void *)&mfc);
+
+       if (retval) {
+               com_err(disk, retval, "while mapping files in %s", directory);
+               exit(X_ABORT);
+       }
+       /*
+        * Ensure that the root inode actually appears in the file list
+        * for a subdir
+        */
+       mapfileino(ROOTINO, 0, tapesize, &anydirskipped);
+       /*
+        * Restore gets very upset if the root is not dumped,
+        * so ensure that it always is dumped.
+        */
+       SETINO(ROOTINO, dumpinomap);
+       return anydirskipped;
+}
+#endif
+
+#ifdef __linux__
+struct mapdirs_context {
+       int *ret;
+       int nodump;
+       long *tapesize;
+};
+#endif
+
+/*
+ * Dump pass 2.
+ *
+ * Scan each directory on the filesystem to see if it has any modified
+ * files in it. If it does, and has not already been added to the dump
+ * list (because it was itself modified), then add it. If a directory
+ * has not been modified itself, contains no modified files and has no
+ * subdirectories, then it can be deleted from the dump list and from
+ * the list of directories. By deleting it from the list of directories,
+ * its parent may now qualify for the same treatment on this or a later
+ * pass using this algorithm.
+ */
+int
+mapdirs(dump_ino_t maxino, long *tapesize)
+{
+       struct  dinode *dp;
+       int isdir;
+       char *map;
+       dump_ino_t ino;
+#ifndef __linux__
+       int i;
+       long filesize;
+#else
+       struct mapdirs_context mdc;
+#endif
+       int ret, change = 0, nodump;
+
+       isdir = 0;              /* XXX just to get gcc to shut up */
+       for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
+               if (((ino - 1) % NBBY) == 0)    /* map is offset by 1 */
+                       isdir = *map++;
+               else
+                       isdir >>= 1;
+               /*
+                * If dir has been removed from the used map, it's either
+                * because it had the nodump flag, or it herited it from
+                * its parent. A directory can't be in dumpinomap if not
+                * in usedinomap, but we have to go through it anyway 
+                * to propagate the nodump attribute.
+                */
+               nodump = (TSTINO(ino, usedinomap) == 0);
+               if ((isdir & 1) == 0 ||
+                   (TSTINO(ino, dumpinomap) && nodump == 0))
+                       continue;
+               dp = getino(ino);
+#ifdef __linux__
+               ret = 0;
+               mdc.ret = &ret;
+               mdc.nodump = nodump;
+               mdc.tapesize = tapesize;
+               ext2fs_dir_iterate(fs, ino, 0, NULL, searchdir, (void *) &mdc);
+#else  /* __linux__ */
+               filesize = dp->di_size;
+               for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) {
+                       if (dp->di_db[i] != 0)
+                               ret |= searchdir(ino, dp->di_db[i],
+                                       (long)dblksize(sblock, dp, i),
+                                       filesize);
+                       if (ret & HASDUMPEDFILE)
+                               filesize = 0;
+                       else
+                               filesize -= sblock->fs_bsize;
+               }
+               for (i = 0; filesize > 0 && i < NIADDR; i++) {
+                       if (dp->di_ib[i] == 0)
+                               continue;
+                       ret |= dirindir(ino, dp->di_ib[i], i, &filesize);
+               }
+#endif /* __linux__ */
+               if (ret & HASDUMPEDFILE) {
+                       SETINO(ino, dumpinomap);
+                       *tapesize += blockest(dp);
+                       change = 1;
+                       continue;
+               }
+               if (nodump) {
+                       if (ret & HASSUBDIRS)
+                               change = 1; /* subdirs have inherited nodump */
+                       CLRINO(ino, dumpdirmap);
+               } else if ((ret & HASSUBDIRS) == 0) {
+                       if (!TSTINO(ino, dumpinomap)) {
+                               CLRINO(ino, dumpdirmap);
+                               change = 1;
+                       }
+               }
+       }
+       return (change);
+}
+
+#ifndef        __linux__
+/*
+ * Read indirect blocks, and pass the data blocks to be searched
+ * as directories. Quit as soon as any entry is found that will
+ * require the directory to be dumped.
+ */
+static int
+dirindir(dump_ino_t ino, daddr_t blkno, int ind_level, long *filesize)
+{
+       int ret = 0;
+       int i;
+       daddr_t idblk[MAXNINDIR];
+
+       bread(fsbtodb(sblock, blkno), (char *)idblk, (int)sblock->fs_bsize);
+       if (ind_level <= 0) {
+               for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
+                       blkno = idblk[i];
+                       if (blkno != 0)
+                               ret |= searchdir(ino, blkno, sblock->fs_bsize,
+                                       *filesize);
+                       if (ret & HASDUMPEDFILE)
+                               *filesize = 0;
+                       else
+                               *filesize -= sblock->fs_bsize;
+               }
+               return (ret);
+       }
+       ind_level--;
+       for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
+               blkno = idblk[i];
+               if (blkno != 0)
+                       ret |= dirindir(ino, blkno, ind_level, filesize);
+       }
+       return (ret);
+}
+#endif /* !__linux__ */
+
+/*
+ * Scan a disk block containing directory information looking to see if
+ * any of the entries are on the dump list and to see if the directory
+ * contains any subdirectories.
+ */
+#ifdef __linux__
+static int
+searchdir(struct ext2_dir_entry *dp, UNUSED(int offset), 
+         UNUSED(int blocksize), UNUSED(char *buf), void *private)
+{
+       struct mapdirs_context *mdc;
+       int *ret;
+       long *tapesize;
+       struct dinode *ip;
+
+       mdc = (struct mapdirs_context *)private;
+       ret = mdc->ret;
+       tapesize = mdc->tapesize;
+
+       if (dp->inode == 0)
+               return 0;
+       if (dp->name[0] == '.') {
+               if (( dp->name_len & 0xFF ) == 1)
+                       return 0;
+               if (dp->name[1] == '.' && ( dp->name_len & 0xFF ) == 2)
+                       return 0;
+       }
+       if (mdc->nodump) {
+               ip = getino(dp->inode);
+               if (TSTINO(dp->inode, dumpinomap)) {
+                       CLRINO(dp->inode, dumpinomap);
+                       *tapesize -= blockest(ip);
+               }
+               /* Add dir back to the dir map and remove from
+                * usedinomap to propagate nodump */
+               if ((ip->di_mode & IFMT) == IFDIR) {
+                       SETINO(dp->inode, dumpdirmap);
+                       CLRINO(dp->inode, usedinomap);
+                       *ret |= HASSUBDIRS;
+               }
+       } else {
+               if (TSTINO(dp->inode, dumpinomap)) {
+                       *ret |= HASDUMPEDFILE;
+                       if (*ret & HASSUBDIRS)
+                               return DIRENT_ABORT;
+               }
+               if (TSTINO(dp->inode, dumpdirmap)) {
+                       *ret |= HASSUBDIRS;
+                       if (*ret & HASDUMPEDFILE)
+                               return DIRENT_ABORT;
+               }
+       }
+       return 0;
+}
+
+#else  /* __linux__ */
+
+static int
+searchdir(dump_ino_t ino, daddr_t blkno, long size, long filesize)
+{
+       struct direct *dp;
+       long loc, ret = 0;
+       char dblk[MAXBSIZE];
+
+       bread(fsbtodb(sblock, blkno), dblk, (int)size);
+       if (filesize < size)
+               size = filesize;
+       for (loc = 0; loc < size; ) {
+               dp = (struct direct *)(dblk + loc);
+               if (dp->d_reclen == 0) {
+                       msg("corrupted directory, inumber %d\n", ino);
+                       break;
+               }
+               loc += dp->d_reclen;
+               if (dp->d_ino == 0)
+                       continue;
+               if (dp->d_name[0] == '.') {
+                       if (dp->d_name[1] == '\0')
+                               continue;
+                       if (dp->d_name[1] == '.' && dp->d_name[2] == '\0')
+                               continue;
+               }
+               if (TSTINO(dp->d_ino, dumpinomap)) {
+                       ret |= HASDUMPEDFILE;
+                       if (ret & HASSUBDIRS)
+                               break;
+               }
+               if (TSTINO(dp->d_ino, dumpdirmap)) {
+                       ret |= HASSUBDIRS;
+                       if (ret & HASDUMPEDFILE)
+                               break;
+               }
+       }
+       return (ret);
+}
+#endif /* __linux__ */
+
+#ifdef __linux__
+
+struct block_context {
+       ext2_ino_t ino;
+       int     *buf;
+       int     cnt;
+       int     max;
+       int     next_block;
+};
+
+/*
+ * Dump a block to the tape
+ */
+static int
+dumponeblock(UNUSED(ext2_filsys fs), blk_t *blocknr, e2_blkcnt_t blockcnt,
+            UNUSED(blk_t ref_block), UNUSED(int ref_offset), void * private)
+{
+       struct block_context *p;
+       e2_blkcnt_t i;
+
+       if (blockcnt < NDADDR)
+               return 0;
+       p = (struct block_context *)private;
+       for (i = p->next_block; i < blockcnt; i++) {
+               p->buf[p->cnt++] = 0;
+               if (p->cnt == p->max) {
+                       blksout (p->buf, p->cnt, p->ino);
+                       p->cnt = 0;
+               }
+       }
+       p->buf[p->cnt++] = *blocknr;
+       if (p->cnt == p->max) {
+               blksout (p->buf, p->cnt, p->ino);
+               p->cnt = 0;
+       }
+       p->next_block = blockcnt + 1;
+       return 0;
+}
+#endif
+
+/*
+ * Dump passes 3 and 4.
+ *
+ * Dump the contents of an inode to tape.
+ */
+void
+dumpino(struct dinode *dp, dump_ino_t ino, int metaonly)
+{
+       unsigned long cnt;
+       fsizeT size, remaining;
+       char buf[TP_BSIZE];
+       struct new_bsd_inode nbi;
+       int i;
+#ifdef __linux__
+       struct block_context bc;
+#else
+       int ind_level;
+#endif
+       u_quad_t i_size;
+       
+       if (metaonly)
+               i_size = 0;
+       else 
+               i_size = dp->di_size + ((u_quad_t) dp->di_size_high << 32);
+
+       if (newtape) {
+               newtape = 0;
+               dumpmap(dumpinomap, TS_BITS, ino);
+       }
+       CLRINO(ino, dumpinomap);
+#ifdef __linux__
+       memset(&nbi, 0, sizeof(nbi));
+       nbi.di_mode = dp->di_mode;
+       nbi.di_nlink = dp->di_nlink;
+       nbi.di_ouid = dp->di_uid;
+       nbi.di_ogid = dp->di_gid;
+       nbi.di_size = i_size;
+       nbi.di_atime.tv_sec = dp->di_atime;
+       nbi.di_mtime.tv_sec = dp->di_mtime;
+       nbi.di_ctime.tv_sec = dp->di_ctime;
+       memmove(&nbi.di_db, &dp->di_db, (NDADDR + NIADDR) * sizeof(daddr_t));
+       nbi.di_flags = dp->di_flags;
+       nbi.di_blocks = dp->di_blocks;
+       nbi.di_gen = dp->di_gen;
+       nbi.di_uid = (((int32_t)dp->di_uidhigh) << 16) | dp->di_uid;
+       nbi.di_gid = (((int32_t)dp->di_gidhigh) << 16) | dp->di_gid;
+       if (dp->di_file_acl)
+               msg("ACLs in inode #%ld won't be dumped\n", (long)ino);
+       memmove(&spcl.c_dinode, &nbi, sizeof(nbi));
+#else  /* __linux__ */
+       spcl.c_dinode = *dp;
+#endif /* __linux__ */
+       spcl.c_type = TS_INODE;
+       spcl.c_count = 0;
+
+       if (metaonly && (dp->di_mode & S_IFMT)) {
+               spcl.c_flags |= DR_METAONLY;
+               spcl.c_count = 0;
+               writeheader(ino);
+               spcl.c_flags &= ~DR_METAONLY;
+               return;
+       }
+
+       switch (dp->di_mode & S_IFMT) {
+
+       case 0:
+               /*
+                * Freed inode.
+                */
+               return;
+
+#ifdef __linux__
+       case S_IFDIR:
+               msg("Warning: dumpino called on a directory (ino %d)\n", ino);
+               return;
+#endif
+
+       case S_IFLNK:
+               /*
+                * Check for short symbolic link.
+                */
+#ifdef __linux__
+               if (i_size > 0 &&
+                   i_size < EXT2_N_BLOCKS * sizeof (daddr_t)) {
+                       spcl.c_addr[0] = 1;
+                       spcl.c_count = 1;
+                       writeheader(ino);
+                       memmove(buf, dp->di_db, (u_long)dp->di_size);
+                       buf[dp->di_size] = '\0';
+                       writerec(buf, 0);
+                       return;
+               }
+#endif /* __linux__ */
+#ifdef FS_44INODEFMT
+               if (dp->di_size > 0 &&
+                   dp->di_size < sblock->fs_maxsymlinklen) {
+                       spcl.c_addr[0] = 1;
+                       spcl.c_count = 1;
+                       writeheader(ino);
+                       memmove(buf, dp->di_shortlink, (u_long)dp->di_size);
+                       buf[dp->di_size] = '\0';
+                       writerec(buf, 0);
+                       return;
+               }
+#endif
+               /* fall through */
+
+#ifndef        __linux__
+       case S_IFDIR:
+#endif
+       case S_IFREG:
+               if (i_size)
+                       break;
+               /* fall through */
+
+       case S_IFIFO:
+       case S_IFSOCK:
+       case S_IFCHR:
+       case S_IFBLK:
+               writeheader(ino);
+               return;
+
+       default:
+               msg("Warning: undefined file type 0%o\n", dp->di_mode & IFMT);
+               return;
+       }
+       if (i_size > (u_quad_t)NDADDR * sblock->fs_bsize)
+#ifdef __linux__
+               cnt = NDADDR * EXT2_FRAGS_PER_BLOCK(fs->super);
+#else
+               cnt = NDADDR * sblock->fs_frag;
+#endif
+       else
+               cnt = howmany(i_size, sblock->fs_fsize);
+       blksout(&dp->di_db[0], cnt, ino);
+       if ((quad_t) (size = i_size - NDADDR * sblock->fs_bsize) <= 0)
+               return;
+#ifdef __linux__
+       bc.max = NINDIR(sblock) * EXT2_FRAGS_PER_BLOCK(fs->super);
+       bc.buf = (int *)malloc (bc.max * sizeof (int));
+       bc.cnt = 0;
+       bc.ino = ino;
+       bc.next_block = NDADDR;
+
+       ext2fs_block_iterate2(fs, (ext2_ino_t)ino, 0, NULL, dumponeblock, (void *)&bc);
+       /* deal with holes at the end of the inode */
+       if (i_size > ((u_quad_t)bc.next_block) * sblock->fs_fsize) {
+               remaining = i_size - ((u_quad_t)bc.next_block) * sblock->fs_fsize;
+               for (i = 0; i < (int)howmany(remaining, sblock->fs_fsize); i++) {
+                       bc.buf[bc.cnt++] = 0;
+                       if (bc.cnt == bc.max) {
+                               blksout (bc.buf, bc.cnt, bc.ino);
+                               bc.cnt = 0;
+                       }
+               }
+       }
+       if (bc.cnt > 0) {
+               blksout (bc.buf, bc.cnt, bc.ino);
+       }
+       free(bc.buf);
+#else
+       for (ind_level = 0; ind_level < NIADDR; ind_level++) {
+               dmpindir(ino, dp->di_ib[ind_level], ind_level, &size);
+               if (size <= 0)
+                       return;
+       }
+#endif
+}
+
+#ifdef __linux__
+
+struct convert_dir_context {
+       char *buf;
+       int prev_offset;
+       int offset;
+       int bs;
+};
+
+/*
+ * This function converts an ext2fs directory entry to the BSD format.
+ *
+ * Basically, it adds a null-character at the end of the name, recomputes the
+ * size of the entry, and creates it in a temporary buffer
+ */
+static int
+convert_dir(struct ext2_dir_entry *dirent, UNUSED(int offset), 
+           UNUSED(int blocksize), UNUSED(char *buf), void *private)
+{
+       struct convert_dir_context *p;
+       struct direct *dp;
+       int reclen;
+
+       p = (struct convert_dir_context *)private;
+
+       reclen = EXT2_DIR_REC_LEN((dirent->name_len & 0xFF) + 1);
+       if (((p->offset + reclen - 1) / p->bs) != (p->offset / p->bs)) {
+               dp = (struct direct *)(p->buf + p->prev_offset);
+               dp->d_reclen += p->bs - (p->offset % p->bs);
+               p->offset += p->bs - (p->offset % p->bs);
+       }
+
+       dp = (struct direct *)(p->buf + p->offset);
+       dp->d_ino = dirent->inode;
+       dp->d_reclen = reclen;
+       dp->d_namlen = dirent->name_len & 0xFF;
+       switch ((dirent->name_len & 0xFF00) >> 8) {
+       default:
+               dp->d_type = DT_UNKNOWN;
+               break;
+       case EXT2_FT_REG_FILE:
+               dp->d_type = DT_REG;
+               break;
+       case EXT2_FT_DIR:
+               dp->d_type = DT_DIR;
+               break;
+       case EXT2_FT_CHRDEV:
+               dp->d_type = DT_CHR;
+               break;
+       case EXT2_FT_BLKDEV:
+               dp->d_type = DT_BLK;
+               break;
+       case EXT2_FT_FIFO:
+               dp->d_type = DT_FIFO;
+               break;
+       case EXT2_FT_SOCK:
+               dp->d_type = DT_SOCK;
+               break;
+       case EXT2_FT_SYMLINK:
+               dp->d_type = DT_LNK;
+               break;
+       }
+       strncpy(dp->d_name, dirent->name, dp->d_namlen);
+       dp->d_name[dp->d_namlen] = '\0';
+       p->prev_offset = p->offset;
+       p->offset += reclen;
+
+       return 0;
+}
+
+/*
+ * Dump pass 3
+ *
+ * Dumps a directory to tape after converting it to the BSD format
+ */
+void
+dumpdirino(struct dinode *dp, dump_ino_t ino)
+{
+       fsizeT size;
+       char buf[TP_BSIZE];
+       struct new_bsd_inode nbi;
+       struct convert_dir_context cdc;
+       errcode_t retval;
+       struct ext2_dir_entry *de;
+       fsizeT dir_size;
+
+       if (newtape) {
+               newtape = 0;
+               dumpmap(dumpinomap, TS_BITS, ino);
+       }
+       CLRINO(ino, dumpinomap);
+
+       /*
+        * Convert the directory to the BSD format
+        */
+       /* Allocate a buffer for the conversion (twice the size of the
+          ext2fs directory to avoid problems ;-) */
+       cdc.buf = (char *)malloc(dp->di_size * 2 * sizeof(char));
+       if (cdc.buf == NULL)
+               err(1, "Cannot allocate buffer to convert directory #%lu\n",
+                   (unsigned long)ino);
+       cdc.offset = 0;
+       cdc.prev_offset = 0;
+       cdc.bs = MIN(DIRBLKSIZ, TP_BSIZE);
+       /* Do the conversion */
+       retval = ext2fs_dir_iterate(fs, (ext2_ino_t)ino, 0, NULL, convert_dir, (void *)&cdc);
+       if (retval) {
+               com_err(disk, retval, "while converting directory #%ld\n", (long)ino);
+               exit(X_ABORT);
+       }
+       /* Fix the last entry */
+       if ((cdc.offset % cdc.bs) != 0) {
+               de = (struct ext2_dir_entry *)(cdc.buf + cdc.prev_offset);
+               de->rec_len += cdc.bs - (cdc.offset % cdc.bs);
+               cdc.offset += cdc.bs - (cdc.offset % cdc.bs);
+       }
+
+       dir_size = cdc.offset;
+
+#ifdef __linux__
+       memset(&nbi, 0, sizeof(nbi));
+       nbi.di_mode = dp->di_mode;
+       nbi.di_nlink = dp->di_nlink;
+       nbi.di_ouid = dp->di_uid;
+       nbi.di_ogid = dp->di_gid;
+       nbi.di_size = dir_size; /* (u_quad_t)dp->di_size; */
+       nbi.di_atime.tv_sec = dp->di_atime;
+       nbi.di_mtime.tv_sec = dp->di_mtime;
+       nbi.di_ctime.tv_sec = dp->di_ctime;
+       memmove(&nbi.di_db, &dp->di_db, (NDADDR + NIADDR) * sizeof(daddr_t));
+       nbi.di_flags = dp->di_flags;
+       nbi.di_blocks = dp->di_blocks;
+       nbi.di_gen = dp->di_gen;
+       nbi.di_uid = (((int32_t)dp->di_uidhigh) << 16) | dp->di_uid;
+       nbi.di_gid = (((int32_t)dp->di_gidhigh) << 16) | dp->di_gid;
+       if (dp->di_file_acl)
+               msg("ACLs in inode #%ld won't be dumped\n", (long)ino);
+       memmove(&spcl.c_dinode, &nbi, sizeof(nbi));
+#else  /* __linux__ */
+       spcl.c_dinode = *dp;
+#endif /* __linux__ */
+       spcl.c_type = TS_INODE;
+       spcl.c_count = 0;
+       switch (dp->di_mode & S_IFMT) {
+
+       case 0:
+               /*
+                * Freed inode.
+                */
+               return;
+
+       case S_IFDIR:
+               if (dir_size > 0)
+                       break;
+               msg("Warning: size of directory inode #%d is <= 0 (%d)!\n",
+                       ino, dir_size);
+               return;
+
+       default:
+               msg("Warning: dumpdirino called with file type 0%o (inode #%d)\n",
+                       dp->di_mode & IFMT, ino);
+               return;
+       }
+       for (size = 0; size < dir_size; size += TP_BSIZE) {
+               spcl.c_addr[0] = 1;
+               spcl.c_count = 1;
+               writeheader(ino);
+               memmove(buf, cdc.buf + size, TP_BSIZE);
+               writerec(buf, 0);
+               spcl.c_type = TS_ADDR;
+       }
+
+       (void)free(cdc.buf);
+}
+#endif /* __linux__ */
+
+#ifndef        __linux__
+/*
+ * Read indirect blocks, and pass the data blocks to be dumped.
+ */
+static void
+dmpindir(dump_ino_t ino, daddr_t blk, int ind_level, fsizeT *size)
+{
+       int i, cnt;
+#ifdef __linux__
+       int max;
+       blk_t *swapme;
+#endif
+       daddr_t idblk[MAXNINDIR];
+
+       if (blk != 0) {
+               bread(fsbtodb(sblock, blk), (char *)idblk, (int) sblock->fs_bsize);
+#ifdef __linux__
+       /* 
+        * My RedHat 4.0 system doesn't have these flags; I haven't
+        * upgraded e2fsprogs yet
+        */
+#if defined(EXT2_FLAG_SWAP_BYTES)
+       if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+           (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+#endif
+       {
+               max = sblock->fs_bsize >> 2;
+               swapme = (blk_t *) idblk;
+               for (i = 0; i < max; i++, swapme++)
+                       *swapme = ext2fs_swab32(*swapme);
+       }
+#endif /* __linux__ */
+       else
+               memset(idblk, 0, (int)sblock->fs_bsize);
+       if (ind_level <= 0) {
+               if (*size < NINDIR(sblock) * sblock->fs_bsize)
+                       cnt = howmany(*size, sblock->fs_fsize);
+               else
+#ifdef __linux__
+                       cnt = NINDIR(sblock) * EXT2_FRAGS_PER_BLOCK(fs->super);
+#else
+                       cnt = NINDIR(sblock) * sblock->fs_frag;
+#endif
+               *size -= NINDIR(sblock) * sblock->fs_bsize;
+               blksout(&idblk[0], cnt, ino);
+               return;
+       }
+       ind_level--;
+       for (i = 0; i < NINDIR(sblock); i++) {
+               dmpindir(ino, idblk[i], ind_level, size);
+               if (*size <= 0)
+                       return;
+       }
+}
+#endif
+
+/*
+ * Collect up the data into tape record sized buffers and output them.
+ */
+void
+blksout(blk_t *blkp, int frags, dump_ino_t ino)
+{
+       blk_t *bp;
+       int i, j, count, blks, tbperdb;
+
+       blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
+       tbperdb = sblock->fs_bsize >> tp_bshift;
+       for (i = 0; i < blks; i += TP_NINDIR) {
+               if (i + TP_NINDIR > blks)
+                       count = blks;
+               else
+                       count = i + TP_NINDIR;
+               for (j = i; j < count; j++)
+                       if (blkp[j / tbperdb] != 0)
+                               spcl.c_addr[j - i] = 1;
+                       else
+                               spcl.c_addr[j - i] = 0;
+               spcl.c_count = count - i;
+               writeheader(ino);
+               bp = &blkp[i / tbperdb];
+               for (j = i; j < count; j += tbperdb, bp++) {
+                       if (*bp != 0) {
+                               if (j + tbperdb <= count)
+                                       dumpblock(*bp, (int)sblock->fs_bsize);
+                               else
+                                       dumpblock(*bp, (count - j) * TP_BSIZE);
+                       }
+               }
+               spcl.c_type = TS_ADDR;
+       }
+}
+
+/*
+ * Dump a map to the tape.
+ */
+void
+dumpmap(char *map, int type, dump_ino_t ino)
+{
+       int i;
+       char *cp;
+
+       spcl.c_type = type;
+       spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE);
+       writeheader(ino);
+       for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE)
+               writerec(cp, 0);
+}
+
+#if defined(__linux__) && !defined(int32_t)
+#define int32_t __s32
+#endif
+
+/* 
+ * Compute and fill in checksum information.
+ */
+void
+mkchecksum(union u_spcl *tmpspcl) 
+{
+       int32_t sum, cnt, *lp;
+
+       tmpspcl->s_spcl.c_checksum = 0;
+       lp = (int32_t *)&tmpspcl->s_spcl;
+       sum = 0;
+       cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t));
+       while (--cnt >= 0) {
+               sum += *lp++;
+               sum += *lp++;
+               sum += *lp++;
+               sum += *lp++;
+       }
+       tmpspcl->s_spcl.c_checksum = CHECKSUM - sum;
+}
+
+/*
+ * Write a header record to the dump tape.
+ */
+void
+writeheader(dump_ino_t ino)
+{
+       spcl.c_inumber = ino;
+       spcl.c_magic = NFS_MAGIC;
+       mkchecksum((union u_spcl *)&spcl);
+       writerec((char *)&spcl, 1);
+}
+
+#ifdef __linux__
+struct dinode *
+getino(dump_ino_t inum)
+{
+       static struct dinode dinode;
+       errcode_t err;
+
+       curino = inum;
+       err = ext2fs_read_inode(fs, (ext2_ino_t)inum, (struct ext2_inode *) &dinode);
+       if (err) {
+               com_err(disk, err, "while reading inode #%ld\n", (long)inum);
+               exit(X_ABORT);
+       }
+       return &dinode;
+}
+#else  /* __linux__ */
+struct dinode *
+getino(dump_ino_t inum)
+{
+       static daddr_t minino, maxino;
+       static struct dinode inoblock[MAXINOPB];
+
+       curino = inum;
+       if (inum >= minino && inum < maxino)
+               return (&inoblock[inum - minino]);
+       bread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), (char *)inoblock,
+           (int)sblock->fs_bsize);
+       minino = inum - (inum % INOPB(sblock));
+       maxino = minino + INOPB(sblock);
+       return (&inoblock[inum - minino]);
+}
+#endif /* __linux__ */
+
+/*
+ * Read a chunk of data from the disk.
+ * Try to recover from hard errors by reading in sector sized pieces.
+ * Error recovery is attempted at most BREADEMAX times before seeking
+ * consent from the operator to continue.
+ */
+int    breaderrors = 0;
+
+void
+bread(ext2_loff_t blkno, char *buf, int size)
+{
+       int cnt, i;
+
+loop:
+#ifdef __linux__
+       if (ext2fs_llseek(diskfd, (blkno << dev_bshift), 0) !=
+                       (blkno << dev_bshift))
+#else
+       if (lseek(diskfd, ((off_t)blkno << dev_bshift), 0) !=
+                                               ((off_t)blkno << dev_bshift))
+#endif
+               msg("bread: lseek fails\n");
+       if ((cnt = read(diskfd, buf, size)) == size)
+               return;
+       if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) {
+               /*
+                * Trying to read the final fragment.
+                *
+                * NB - dump only works in TP_BSIZE blocks, hence
+                * rounds `dev_bsize' fragments up to TP_BSIZE pieces.
+                * It should be smarter about not actually trying to
+                * read more than it can get, but for the time being
+                * we punt and scale back the read only when it gets
+                * us into trouble. (mkm 9/25/83)
+                */
+               size -= dev_bsize;
+               goto loop;
+       }
+       if (cnt == -1)
+               msg("read error from %s: %s: [block %d, ext2blk %d]: count=%d\n",
+                       disk, strerror(errno), blkno, 
+                       dbtofsb(sblock, blkno), size);
+       else
+               msg("short read error from %s: [block %d, ext2blk %d]: count=%d, got=%d\n",
+                       disk, blkno, dbtofsb(sblock, blkno), size, cnt);
+       if (breademax && ++breaderrors > breademax) {
+               msg("More than %d block read errors from %d\n",
+                       breademax, disk);
+               broadcast("DUMP IS AILING!\n");
+               msg("This is an unrecoverable error.\n");
+               if (!query("Do you want to attempt to continue?")){
+                       dumpabort(0);
+                       /*NOTREACHED*/
+               } else
+                       breaderrors = 0;
+       }
+       /*
+        * Zero buffer, then try to read each sector of buffer separately.
+        */
+       memset(buf, 0, size);
+       for (i = 0; i < size; i += dev_bsize, buf += dev_bsize, blkno++) {
+#ifdef __linux__
+               if (ext2fs_llseek(diskfd, (blkno << dev_bshift), 0) !=
+                               (blkno << dev_bshift))
+#else
+               if (lseek(diskfd, ((off_t)blkno << dev_bshift), 0) !=
+                                               ((off_t)blkno << dev_bshift))
+#endif
+                       msg("bread: lseek2 fails!\n");
+               if ((cnt = read(diskfd, buf, (int)dev_bsize)) == dev_bsize)
+                       continue;
+               if (cnt == -1) {
+                       msg("read error from %s: %s: [sector %d, ext2blk %d]: count=%d\n",
+                               disk, strerror(errno), blkno, 
+                               dbtofsb(sblock, blkno), dev_bsize);
+                       continue;
+               }
+               msg("short read error from %s: [sector %d, ext2blk %d]: count=%d, got=%d\n",
+                       disk, blkno, dbtofsb(sblock, blkno), dev_bsize, cnt);
+       }
+}
diff --git a/dump/unctime.c b/dump/unctime.c
new file mode 100644 (file)
index 0000000..684719d
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*-
+ * Copyright (c) 1980, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: unctime.c,v 1.16 2003/03/30 15:40:37 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <sys/time.h>
+#include <time.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include <sys/param.h>
+#include <stdio.h>
+
+#ifdef __linux__
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>
+#include <bsdcompat.h>
+#endif
+
+#include "dump.h"
+
+/*
+ * Convert a ctime(3) format string into a system format date.
+ * Return the date thus calculated.
+ *
+ * Return -1 if the string is not in ctime format.
+ */
+
+/*
+ * Offsets into the ctime string to various parts.
+ */
+
+#define        E_MONTH         4
+#define        E_DAY           8
+#define        E_HOUR          11
+#define        E_MINUTE        14
+#define        E_SECOND        17
+#define        E_YEAR          20
+#define E_TZOFFSET      25
+
+static int lookup __P((const char *));
+
+
+time_t
+unctime(const char *str)
+{
+       struct tm then;
+       char dbuf[32];
+       time_t rtime;
+       int tzoffset;
+
+       (void) strncpy(dbuf, str, sizeof(dbuf) - 1);
+       dbuf[sizeof(dbuf) - 1] = '\0';
+       dbuf[E_MONTH+3] = '\0';
+       if ((then.tm_mon = lookup(&dbuf[E_MONTH])) < 0)
+               return (-1);
+       then.tm_mday = atoi(&dbuf[E_DAY]);
+       then.tm_hour = atoi(&dbuf[E_HOUR]);
+       then.tm_min = atoi(&dbuf[E_MINUTE]);
+       then.tm_sec = atoi(&dbuf[E_SECOND]);
+       then.tm_year = atoi(&dbuf[E_YEAR]) - 1900;
+       then.tm_isdst = -1;
+       if (strlen(str) >= E_TZOFFSET+5) {
+               rtime = timegm(&then);
+               /* add timezone offset */
+               tzoffset = atoi(&dbuf[E_TZOFFSET]);
+               rtime -= (tzoffset / 100 * 3600) + (tzoffset % 100) * 60;
+       } else {
+               rtime = timelocal(&then);
+       }
+       return(rtime);
+}
+
+static char months[] =
+       "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+static int
+lookup(const char *str)
+{
+       const char *cp, *cp2;
+
+       for (cp = months, cp2 = str; *cp != '\0'; cp += 3)
+               if (strncmp(cp, cp2, 3) == 0)
+                       return((cp-months) / 3);
+       return(-1);
+}
diff --git a/examples/cron_dump_to_disk/README b/examples/cron_dump_to_disk/README
new file mode 100644 (file)
index 0000000..5301f17
--- /dev/null
@@ -0,0 +1,31 @@
+Here is how to use these backup scripts:
+
+1. Create a separate backup partition big enough to hold all the filesystems you want to backup + any changes. Preferably, get a big inexpensive ide drive, and dedicate it as a backup drive.
+
+2. Create the mount point for the partition as /backup (otherwise, modify the config parameters at the top of the scripts).
+
+3. Mount the partition read-write, cd into /backup, and extract the backupskel.tar.gz there. This will create the directory structure needed by the scripts.
+
+4. Set the partition to be mounted as read-only in your /etc/fstab. This will protect your precious backup from software crashes.
+
+5. Copy the backup scripts "backup" and "backup_rotate" to a suitable directory in cron's path; "/usr/bin" is a good location. alternatively, you can place them anywhere, and modify the crontab entries to match, or run it manually.
+
+6. Modify your /etc/crontab file to add these entries, and be sure to modify the times to suit your preferences, and the performance of your machine:
+
+----------%<---------------------------------%<--------------------------------
+
+# Perform Nightly Backup (nightly incremental + weekly full + monthly full)
+02 06 * * 1-6 root backup_rotate ; nice -1 backup inc
+02 06 * * sun root backup_rotate ; nice -1 backup full
+07 00 01 * * root backup_rotate monthly ; backup full nodumpdate
+
+----------%<---------------------------------%<--------------------------------
+
+Any questions? Send me and email to getnito@yahoo.com.
+
+And that is it. Have fun!
+
+--
+nito
+
+getnito@yahoo.com
diff --git a/examples/cron_dump_to_disk/backup b/examples/cron_dump_to_disk/backup
new file mode 100755 (executable)
index 0000000..da6bda6
--- /dev/null
@@ -0,0 +1,179 @@
+#!/bin/bash
+#
+# This script will make a simple backup of the most critical partitions,
+# using the "dump" facility, into the backup partition. It will stop the
+# webserver, and recurse the sites directories making a tar mini-backup of
+# the database dirs. It will the restart the webserver, and start the
+# "dump" backup.
+#
+
+if [ "$2" = "nodumpdate" ]; then
+   UPDATEDDATE=""
+else
+   UPDATEDDATE="-u"
+fi
+
+if [ "$1" = "full" ]; then
+   DLEVEL="0"
+   BTYPE="full"
+elif [ "$1" = "inc" ]; then
+   DLEVEL="1"
+   BTYPE="inc"
+else
+   echo "Usage: $0 full|inc [nodumpdate]" 
+   exit 1
+fi
+
+
+#
+# Configuration Parameters
+#
+
+BACKUPPART="/backup"
+BACKUPDIR="current"
+DUMPLOGARCH="$BACKUPPART/backup.dump.log.gz"
+FSTODUMP="/ /var /home /mnt/hdb1 /usr"
+DUMPFILESMODE="0644"
+DUMPFILESOWN="root.root"
+
+#
+# Start
+# 
+
+echo
+echo "#####################################################################"
+echo "Starting backup."
+echo "#####################################################################"
+echo
+
+
+#
+#  Make full system backup
+#
+
+echo "Phase 1: ### Full System Dump Backup ###"
+echo "Phase 1: Using backup partition: $BACKUPPART"
+echo "Phase 1: Filesystems to dump: $FSTODUMP"
+
+echo -n "Phase 1: Remounting backup partition read-write ... "
+if ( mount $BACKUPPART -o remount,rw &> /dev/null ) then
+   echo "done."
+else
+   echo "failure!"
+   echo "Phase 1:  There were problems remounting $BACKUPPART in read-write mode!"
+   echo "Phase 1: Aborting Full System Dump Backup."
+   echo "Phase 1: Aborted, done."
+   echo "-------------------------------------------------------------------------------"
+   exit 1
+fi
+
+echo -n "Phase 1: Checking backup partition for correct dir structure ... "
+if [ -d $BACKUPPART/$BACKUPDIR -a -w $BACKUPPART/$BACKUPDIR ]; then
+   echo "done."
+
+   echo -n "Phase 1: Checking backup partition for available space ... "
+   SREQ=`for i in $FSTODUMP;do dump -$DLEVEL -S $i 2> /dev/null;done|awk '{x=x+$1/1048576} END {printf "%6.0f\n", x}'`
+   SAVAILFREE=`df --block-size=1048576 |grep -Ew $BACKUPPART|awk '{printf "%6.0f\n", $4}'`
+   SAVAILDEL=`du -s --block-size=1048576 $BACKUPPART/$BACKUPDIR/. |awk '{printf "%6.0f\n", $1}'`
+   SAVAIL=`expr $SAVAILFREE + $SAVAILDEL`
+
+   if [ `expr $SAVAIL - $SREQ` -gt "0" ]; then
+      echo "done."
+      echo "Phase 1:  Available: $SAVAIL MB Required: $SREQ MB."
+   else
+      echo "no enough space!"
+      echo "Phase 1:  There is not enough space left in $BACKUPPART for the backup!"
+      echo "Phase 1:  Available: $SAVAIL MB Required: $SREQ MB."
+      echo -n "Phase 1: Remounting backup partition read-only ... "
+      if ( mount $BACKUPPART -o remount,ro &> /dev/null ) then
+         echo "done."
+      else
+         echo "failure!"
+         echo "Phase 1:  There were problems remounting $BACKUPPART in read-only mode!"
+         echo "Phase 1: Aborting Full System Dump Backup."
+         echo "Phase 1: Aborted, done."
+         echo "-------------------------------------------------------------------------------"
+         exit 1
+      fi
+      echo "Phase 1: Aborting Full System Dump Backup."
+      echo "Phase 1: Aborted, done."
+      echo "-------------------------------------------------------------------------------"
+      exit 1
+   fi
+
+   echo -n "Phase 1: Deleting old files ... "
+   if [ `ls -la $BACKUPPART/$BACKUPDIR/|wc -l` -gt "3" ]; then
+      rm -f $BACKUPPART/$BACKUPDIR/* &> /dev/null
+      echo "done."
+   else
+      echo "no old files to delete."
+   fi
+
+   echo "Phase 1: Dumping filesystems ... "
+   for FS in $FSTODUMP
+   do
+      if [ "$FS" = "/" ]; then
+         FSNAME="root"
+      else
+         FSNAME=`echo $FS|tr / _|cut -b 2-`
+      fi
+      sync
+      echo -n "Phase 1:  Starting dump of $FSNAME ( $FS ) ... "
+      if ( dump -$DLEVEL $UPDATEDDATE -z -M -s 27306 -f $BACKUPPART/$BACKUPDIR/$FSNAME.$BTYPE. $FS &> $BACKUPPART/$BACKUPDIR/$FSNAME.log ) then
+         echo "done."
+      else
+         echo "problems!"
+         echo "Phase 1:  There where problems with the dump of $FSNAME ( $FS )."
+         echo "Phase 1:  Check logfile $BACKUPPART/$BACKUPDIR/$FSNAME.log for more info"
+         echo "Phase 1:  Also check log archive file $DUMPLOGARCH."
+      fi
+      cat $BACKUPPART/$BACKUPDIR/$FSNAME.log |gzip >> $DUMPLOGARCH
+      echo "-------------------------------------------------------------------------------" |gzip >> $DUMPLOGARCH
+   done
+
+   echo -n "Phase 1: Setting ownership and permissions of dump files ... "
+   chmod $DUMPFILESMODE $BACKUPPART/$BACKUPDIR/* $DUMPLOGARCH &> /dev/null
+   chown $DUMPFILESOWN $BACKUPPART/$BACKUPDIR/* $DUMPLOGARCH &> /dev/null
+   echo "done."
+
+   echo -n "Phase 1: Compressing dump log files ... "
+   gzip $BACKUPPART/$BACKUPDIR/*.log &> /dev/null
+   echo "done."
+   sync
+
+else
+   echo "problems!"
+   echo "Phase 1:  There are problems with the directory structure."
+   echo "Phase 1:  Check dirs: $BACKUPPART/$BACKUPDIR"
+   echo -n "Phase 1: Remounting backup partition read-only ... "
+   if ( mount $BACKUPPART -o remount,ro &> /dev/null ) then
+      echo "done."
+   else
+      echo "failure!"
+      echo "Phase 1:  There were problems remounting $BACKUPPART in read-only mode!"
+      echo "Phase 1: Aborting Full System Dump Backup."
+      echo "Phase 1: Aborted, done."
+      echo "-------------------------------------------------------------------------------"
+      exit 1
+   fi
+   echo "Phase 1: Aborting Full System Dump Backup."
+   echo "Phase 1: Aborted, done."
+   echo "-------------------------------------------------------------------------------"
+   exit 1
+fi
+
+echo -n "Phase 1: Remounting backup partition read-only ... "
+if ( mount $BACKUPPART -o remount,ro &> /dev/null ) then 
+   echo "done."
+else
+   echo "failure!"
+   echo "Phase 1:  There were problems remounting $BACKUPPART in read-only mode!"
+   echo "Phase 1: Aborting Full System Dump Backup."
+   echo "Phase 1: Aborted, done."
+   echo "-------------------------------------------------------------------------------"
+   exit 1
+fi
+
+echo "Phase 1: End of Full System Dump Backup."
+echo "Phase 1: Done."
+echo "-------------------------------------------------------------------------------"
diff --git a/examples/cron_dump_to_disk/backup_rotate b/examples/cron_dump_to_disk/backup_rotate
new file mode 100755 (executable)
index 0000000..2e8eeb9
--- /dev/null
@@ -0,0 +1,90 @@
+#!/bin/bash
+#
+# This script will redirect the backup directory to implement desired backup
+# schedules.
+#
+# Currently we will use just a seven day format were we just move a link
+# that represents the backup directory, to point to the day of the week.
+#
+
+#
+# Configuration Parameters
+#
+
+if [ "$1" = "monthly" ]; then
+   REALDIR="monthly"
+else
+   REALDIR=`date +%A`
+fi
+
+BACKUPPART="/backup"
+BACKUPDIR="current"
+
+echo "### Start of Backup Rotation ###"
+echo "Using backup partition: $BACKUPPART"
+
+echo -n "Remounting backup partition read-write ... "
+if ( mount $BACKUPPART -o remount,rw &> /dev/null ) then
+   echo "done."
+else
+   echo "failure!"
+   echo "   There were problems remounting $BACKUPPART in read-write mode!"
+   echo "Rotation not made!"
+   echo "### End of Backup Rotation ###"
+   exit 1
+fi
+
+echo -n "Checking that no directory named \"$BACKUPDIR\" exists ... "
+if [ -d $BACKUPPART/$BACKUPDIR -a ! -L $BACKUPPART/$BACKUPDIR ]; then
+   echo "failure!"
+   echo "   Directory \"$BACKUPDIR\" exists. Can't create link!"
+   echo "Rotation not made!"
+
+   echo -n "Remounting backup partition read-only ... "
+   if ( mount $BACKUPPART -o remount,ro &> /dev/null ) then
+      echo "done."
+   else
+      echo "failure!"
+      echo "   There were problems remounting $BACKUPPART in read-only mode!"
+      echo "### End of Backup Rotation ###"
+      exit 1
+   fi
+   echo "### End of Backup Rotation ###"
+   exit 1
+else
+   echo "done."
+fi
+
+cd $BACKUPPART
+
+echo -n "Creating link: $BACKUPDIR --> $REALDIR ... "
+if ( ln -snf $REALDIR $BACKUPDIR &> /dev/null ) then
+   echo "done."
+else
+   echo "failure!"
+   echo "   There were problems creating link!"
+   echo "Rotation not made!"
+
+   echo -n "Remounting backup partition read-only ... "
+   if ( mount $BACKUPPART -o remount,ro &> /dev/null ) then
+      echo "done."
+   else
+      echo "failure!"
+      echo "   There were problems remounting $BACKUPPART in read-only mode!"
+      echo "### End of Backup Rotation ###"
+      exit 1
+   fi 
+   echo "### End of Backup Rotation ###"
+   exit 1
+fi
+
+echo -n "Remounting backup partition read-only ... "
+if ( mount $BACKUPPART -o remount,ro &> /dev/null ) then
+   echo "done."
+else
+   echo "failure!"
+   echo "   There were problems remounting $BACKUPPART in read-only mode!"
+   echo "### End of Backup Rotation ###"
+   exit 1
+fi
+echo "### End of Backup Rotation ###"
diff --git a/examples/cron_dump_to_disk/backupskel.tar.gz b/examples/cron_dump_to_disk/backupskel.tar.gz
new file mode 100644 (file)
index 0000000..68614a9
Binary files /dev/null and b/examples/cron_dump_to_disk/backupskel.tar.gz differ
diff --git a/examples/cron_dump_to_disk/crontab_entries.txt b/examples/cron_dump_to_disk/crontab_entries.txt
new file mode 100644 (file)
index 0000000..f7ca35e
--- /dev/null
@@ -0,0 +1,4 @@
+# Perform Nightly Backup (nightly incremental + weekly full + monthly full)
+02 06 * * 1-6 root backup_rotate ; nice -1 backup inc
+02 06 * * sun root backup_rotate ; nice -1 backup full
+07 00 01 * * root backup_rotate monthly ; backup full nodumpdate
diff --git a/examples/dump_on_cd/README b/examples/dump_on_cd/README
new file mode 100644 (file)
index 0000000..ae04ce5
--- /dev/null
@@ -0,0 +1,53 @@
+                    Experimental dump to CDROMs
+                    ===========================
+
+Starting with dump/restore version 0.4b24 or later versions of 
+dump/restore you can dump to CDROMs.
+
+You need a (successfully installed) CD-writing software like
+  cdrecord (tested with versions 1.11a04 onwards)
+
+These scripts use the new switch ('V') to restore
+which signals a multi-volume (non-tape) medium like CDROMs
+
+I have used the shell scripts below to generate/verify the dump
+
+YOU MUST MODIFY these - especially
+
+- adapt FS to the filesystem to be dumped
+- UserExit to the path to the user exit function like UserInfo below
+- FiFo     to the path to a named pipe (better not on the same filesystem)
+- your cd device(s)  ( I have /dev/cdrom a symlink to /dev/sr0 and
+                              /dev/cdrw  a symlink to /dev/sr1 )
+- your path to cdrecord and
+- - cdrecord's dev parameter must be adapted to your CD burner
+- - cdrecord's fs (= input fifo size), use less than 64m if you
+    are short of memory
+- - cdrecord's speed parameter : this parameter not only depends on the
+    capabilities of your CD burner BUT also on the speed of your CPU !!!
+    With the dump -z6 compression on a 900 MHz Pentium III I had no problems
+    with speed=4 which is the maximum speed for my burner.
+    It looks as if at least speed=6 would be possible on a 900 MHz Pentium III.
+    If speed is to large, cdrecord's input fifo gets empty (as
+    shown by cdrecord) and then you have a buffer underrun.
+
+- replace the wayplay command with something which alerts you if you
+  have to change CDROMS
+
+- for restore or verification  replace /dev/cdrom by something
+  which applies for you (device for the CDreader)
+
+
+DON'T FORGET  to generate a boot-CD which has the 0.4b24 restore
+  or a newer version of restore on board
+
+I prefer timos_Rescue_Cd_Set-0.6.1  see  http://rescuecd.sourceforge.net
+
+
+Please Cc bug-reports to  jarausch@igpm.rwth-aachen.de
+
+-----------------------------------------------------------------
+This file and the scripts were slightly edited when the 
+Helmut Jarausch patch was integrated in dump-0.4b24.
+                                               Stelian.
+
diff --git a/examples/dump_on_cd/dump_userinfo.sh b/examples/dump_on_cd/dump_userinfo.sh
new file mode 100755 (executable)
index 0000000..9096048
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+# $1 = filename
+# $2 = sequence number
+
+wavplay -q /root/alert.wav
+num=$[$2+1]
+echo "insert next CD (number $num) "
+read -p "CD number $num ready? " Ans
+
+xterm -hold -T cdrecord_$num -e \
+  /usr/local/bin/cdrecord dev=0,1,0 fs=64m  \
+    -v speed=4 -eject -pad -data $1  &
diff --git a/examples/dump_on_cd/start_dump.sh b/examples/dump_on_cd/start_dump.sh
new file mode 100755 (executable)
index 0000000..df98c0a
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+if [ `id -u` != 0 ]; then 
+  echo "root priviledges are required"
+  exit 1
+fi
+Level=0
+Label=`date -I`
+#CD_Cap=650
+CD_Cap=700
+eval Cap=$(($CD_Cap*1024))
+FS=/
+UserExit=/root/dump_userinfo.sh
+FiFo=/tmp/dump.fifo
+rm -f $FiFo
+mkfifo $FiFo
+xterm -T cdrecord_1 -hold -e cdrecord dev=0,1,0 fs=64m \
+    -v speed=4 -eject -pad -data $FiFo &
+
+/sbin/dump -z6 -b64 -B$Cap -F $UserExit \
+ -$Level -L $Label -f $FiFo  $FS
+
+wavplay -q /root/alert.wav
+rm -f $FiFo
+
diff --git a/examples/dump_on_cd/verify_dump.sh b/examples/dump_on_cd/verify_dump.sh
new file mode 100755 (executable)
index 0000000..2b19702
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+if [ `id -u` != 0 ]; then 
+  echo "root priviledges are required"
+  exit 1
+fi
+cd /
+/sbin/restore -V -b64 -C -f /dev/cdrom
diff --git a/examples/dump_on_cd_2/DE/backup_CD b/examples/dump_on_cd_2/DE/backup_CD
new file mode 100644 (file)
index 0000000..06f7c97
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash
+# This script dumps the specified Filesystem via dump on a CD/DVD
+# CD_CAPACITY defines the capacity in MB per CD
+# The script for the next volume is passed via the -F option of dump
+# !!! do NOT forget to change CD_CAPACITY in $EXITSCRIPT !!!
+COMPRESSION_LEVEL=2
+RECORD_BIN="/usr/bin/cdrecord dev=0,0,0 speed=10 fs=64M -v -dao -eject -pad "
+EXITSCRIPT="/root/bin/cd_dump_userexit"
+FILESYSTEM="/home"
+LEVEL=0
+LABEL="`date -I`"
+# !!! do NOT forget to change CD_CAPACITY in $EXITSCRIPT !!!
+# CD_CAPACITY=650
+CD_CAPACITY=700
+TSIZE="$(echo "$CD_CAPACITY*1024*1024" | bc -l )"
+BSIZE="$(echo "$CD_CAPACITY*1024" | bc -l )"
+FIFO="/tmp/dump.fifo"
+DUMP_BIN="/usr/sbin/dump -z$COMPRESSION_LEVEL -b64 -B$BSIZE -F $EXITSCRIPT -$LEVEL -L $LABEL -f $FIFO $FILESYSTEM"
+
+rm -f $FIFO
+mkfifo $FIFO
+ANSWER=""
+while [ "$ANSWER" != "j" ] ; do  
+       read -p "Ist die CD No. 1 eingelegt? (j/n)" ANSWER
+       if [ "$ANSWER" == "j" ] ; then
+               $RECORD_BIN -tsize=$TSIZE -data $FIFO &
+               $DUMP_BIN 
+               rm -f $FIFO
+               exit 0
+       else
+               EXIT=""
+               read -p "Wollen Sie abbrechen? (j/n)" EXIT
+               if [ "$EXIT" == "j" ] ; then
+                       exit 1
+               fi
+       fi
+done
diff --git a/examples/dump_on_cd_2/DE/backup_DVD b/examples/dump_on_cd_2/DE/backup_DVD
new file mode 100644 (file)
index 0000000..fbee957
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+# This script dumps the specified Filesystem via dump on a CD/DVD
+# CD_CAPACITY defines the capacity in MB per CD
+# The script for the next volume is passed via the -F option of dump
+# At least for my DVD-Recorder (a PHILIPS DVR-A03) it is necessary
+# to define the tracksize for the next track before the DVD is written.
+# This is done via the -tsize option of cdrecord. Since tsize takes its
+# arguments in Bytes, the shell cannot compute the value correctly
+# anymore (value too high), so I use bc.
+
+# !!! If you plan to write DVD's with other sizes, please correct the
+# CD_CAPACITY in the dump_userexit_DVD script, too !!!
+
+COMPRESSION_LEVEL=2
+RECORD_BIN="/usr/bin/dvdrecord dev=0,0,0 fs=64M speed=2 "
+EXITSCRIPT="/root/bin/dvd_dump_userexit"
+FILESYSTEM="/home"
+LEVEL=0
+LABEL="`date -I`"
+CD_CAPACITY=4300
+TSIZE="$(echo "$CD_CAPACITY*1024*1024" | bc -l )"
+BSIZE="$(echo "$CD_CAPACITY*1024" | bc -l )"
+FIFO="/tmp/dump.fifo"
+DUMP_BIN="/usr/sbin/dump -z$COMPRESSION_LEVEL -b64 -B$BSIZE -F $EXITSCRIPT -$LEVEL -L $LABEL -f $FIFO $FILESYSTEM"
+
+rm -f $FIFO
+mkfifo $FIFO
+ANSWER=""
+while [ "$ANSWER" != "j" ] ; do  
+       read -p "Ist die DVD No. 1 eingelegt? (j/n)" ANSWER
+       if [ "$ANSWER" == "j" ] ; then
+               $RECORD_BIN -blank=fast
+               $RECORD_BIN -eject -dao -pad -tsize=$TSIZE -data $FIFO &
+               $DUMP_BIN 
+               rm -f $FIFO
+               exit 0
+       elif [ "$ANSWER" == "n" ] ; then
+               EXIT=""
+               read -p "Wollen Sie abbrechen? (j/n)" EXIT
+               if [ "$EXIT" == "j" ] ; then
+                       exit 1
+               fi
+       fi
+done
diff --git a/examples/dump_on_cd_2/DE/dump_userexit_CD b/examples/dump_on_cd_2/DE/dump_userexit_CD
new file mode 100644 (file)
index 0000000..a8f8db8
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+# supplied info from "dump -F":
+# $1 = filename
+# $2 = sequence number
+
+NUM=$(($2+1))
+RECORD_BIN="/usr/bin/cdrecord speed=10 dev=0,0,0 fs=64M "
+# CD_CAPACITY=700
+# TSIZE="$(echo "$CD_CAPACITY*1024*1024" | bc -l )"
+echo -e "Bitte die naechste CD einlegen (No. $NUM)\n"
+ANSWER=""
+while [ "$ANSWER" != "j" ] ; do
+       read -p "Ist die CD bereit? (j/n)" ANSWER
+       if [ "$ANSWER" == "j" ] ; then
+               $RECORD_BIN -eject -pad -data $1 &
+               exit 0
+       elif [ "$ANSWER" == "n" ] ; then
+               EXIT=""
+               read -p "Wollen Sie abbrechen? (j/n)" EXIT
+               if [ "$EXIT" == "j" ] ; then
+                       exit 1
+               fi
+       fi
+done
diff --git a/examples/dump_on_cd_2/DE/dump_userexit_DVD b/examples/dump_on_cd_2/DE/dump_userexit_DVD
new file mode 100644 (file)
index 0000000..bdfe22a
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/bash
+# supplied info from "dump -F":
+# $1 = filename
+# $2 = sequence number
+
+NUM=$(($2+1))
+RECORD_BIN="/usr/bin/dvdrecord dev=0,0,0 fs=64M speed=2 "
+CD_CAPACITY=4300
+TSIZE="$(echo "$CD_CAPACITY*1024*1024" | bc -l )"
+echo "Bitte die naechste DVD einlegen (No. $NUM)"
+ANSWER=""
+while [ "$ANSWER" != "j" ] ; do
+       read -p "Ist die DVD bereit? (j/n)" ANSWER
+       if [ "$ANSWER" == "j" ] ; then
+               $RECORD_BIN -blank=fast
+               $RECORD_BIN -dao -eject -pad -tsize=$TSIZE -data $1 &
+               exit 0
+       elif [ "$ANSWER" == "n" ] ; then
+               EXIT=""
+               read -p "Wollen Sie abbrechen? (j/n)" EXIT
+               if [ "$EXIT" == "j" ] ; then
+                       exit 1
+               fi
+       fi
+done
diff --git a/examples/dump_on_cd_2/EN/backup_CD b/examples/dump_on_cd_2/EN/backup_CD
new file mode 100644 (file)
index 0000000..94ae81d
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/bash
+# This script dumps the specified Filesystem via dump on a CD/DVD
+# CD_CAPACITY defines the capacity in MB per CD
+# The script for the next volume is passed via the -F option of dump
+# FILESYSTEM defines the filesystem to back up
+COMPRESSION_LEVEL=2
+RECORD_BIN="/usr/bin/dvdrecord dev=0,0,0 fs=64M speed=2 "
+EXITSCRIPT="/root/bin/dvd_dump_userexit"
+FILESYSTEM="/home"
+LEVEL=0
+LABEL="`date -I`"
+CD_CAPACITY=700
+TSIZE="$(echo "$CD_CAPACITY*1024*1024" | bc -l )"
+BSIZE="$(echo "$CD_CAPACITY*1024" | bc -l )"
+FIFO="/tmp/dump.fifo"
+DUMP_BIN="/usr/sbin/dump -z$COMPRESSION_LEVEL -b64 -B$BSIZE -F $EXITSCRIPT -$LEVEL -L $LABEL -f $FIFO $FILESYSTEM"
+
+rm -f $FIFO
+mkfifo $FIFO
+ANSWER=""
+while [ "$ANSWER" != "y" ] ; do  
+       read -p "Did you insert CD No. 1? (y/n)" ANSWER
+       if [ "$ANSWER" == "y" ] ; then
+               $RECORD_BIN -blank=fast
+               $RECORD_BIN -eject -pad -tsize=$TSIZE -data $FIFO &
+               $DUMP_BIN 
+               rm -f $FIFO
+               exit 0
+       elif [ "$ANSWER" == "n" ] ; then
+               EXIT=""
+               read -p "Do you really want to exit? (y/n)" EXIT
+               if [ "$EXIT" == "y" ] ; then
+                       exit 1
+               fi
+       fi
+done
diff --git a/examples/dump_on_cd_2/EN/backup_DVD b/examples/dump_on_cd_2/EN/backup_DVD
new file mode 100644 (file)
index 0000000..518e95b
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+# This script dumps the specified Filesystem via dump on a CD/DVD
+# CD_CAPACITY defines the capacity in MB per CD
+# The script for the next volume is passed via the -F option of dump
+# At least for my DVD-Recorder (a PHILIPS DVR-A03) it is necessary
+# to define the tracksize for the next track before the DVD is written.
+# This is done via the -tsize option of cdrecord. Since tsize takes its
+# arguments in Bytes, the shell cannot compute the value correctly
+# anymore (value too high), so I use bc.
+
+# !!! If you plan to write DVD's with other sizes, please correct the
+# CD_CAPACITY in the dump_userexit_DVD script, too !!!
+
+COMPRESSION_LEVEL=2
+RECORD_BIN="/usr/bin/dvdrecord dev=0,0,0 fs=64M speed=2 "
+EXITSCRIPT="/root/bin/dvd_dump_userexit"
+FILESYSTEM="/home"
+LEVEL=0
+LABEL="`date -I`"
+CD_CAPACITY=4300
+TSIZE="$(echo "$CD_CAPACITY*1024*1024" | bc -l )"
+BSIZE="$(echo "$CD_CAPACITY*1024" | bc -l )"
+FIFO="/tmp/dump.fifo"
+DUMP_BIN="/usr/sbin/dump -z$COMPRESSION_LEVEL -b64 -B$BSIZE -F $EXITSCRIPT -$LEVEL -L $LABEL -f $FIFO $FILESYSTEM"
+
+rm -f $FIFO
+mkfifo $FIFO
+ANSWER=""
+while [ "$ANSWER" != "y" ] ; do  
+       read -p "Did you insert DVD No. 1? (y/n)" ANSWER
+       if [ "$ANSWER" == "y" ] ; then
+               $RECORD_BIN -blank=fast
+               $RECORD_BIN -eject -dao -pad -tsize=$TSIZE -data $FIFO &
+               $DUMP_BIN 
+               rm -f $FIFO
+               exit 0
+       elif [ "$ANSWER" == "n" ] ; then
+               EXIT=""
+               read -p "Do you really want to exit? (y/n)" EXIT
+               if [ "$EXIT" == "y" ] ; then
+                       exit 1
+               fi
+       fi
+done
diff --git a/examples/dump_on_cd_2/EN/dump_userexit_CD b/examples/dump_on_cd_2/EN/dump_userexit_CD
new file mode 100644 (file)
index 0000000..cb45989
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/bash
+# supplied info from "dump -F":
+# $1 = filename
+# $2 = sequence number
+
+NUM=$(($2+1))
+RECORD_BIN="/usr/bin/dvdrecord dev=0,0,0 fs=64M speed=2 "
+echo "Please insert the next CD (No. $NUM)"
+ANSWER=""
+while [ "$ANSWER" != "y" ] ; do
+       read -p "Is the CD ready? (y/n)" ANSWER
+       if [ "$ANSWER" == "y" ] ; then
+               $RECORD_BIN -blank=fast
+               $RECORD_BIN -eject -pad -data $1 &
+               exit 0
+       elif [ "$ANSWER" == "n" ] ; then
+               EXIT=""
+               read -p "Do you really want to exit? (y/n)" EXIT
+               if [ "$EXIT" == "y" ] ; then
+                       exit 1
+               fi
+       fi
+done
diff --git a/examples/dump_on_cd_2/EN/dump_userexit_DVD b/examples/dump_on_cd_2/EN/dump_userexit_DVD
new file mode 100644 (file)
index 0000000..e5fcef4
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/bash
+# supplied info from "dump -F":
+# $1 = filename
+# $2 = sequence number
+
+NUM=$(($2+1))
+RECORD_BIN="/usr/bin/dvdrecord dev=0,0,0 fs=64M speed=2 "
+CD_CAPACITY=4300
+TSIZE="$(echo "$CD_CAPACITY*1024*1024" | bc -l )"
+echo "Please insert the next DVD (No. $NUM)"
+ANSWER=""
+while [ "$ANSWER" != "y" ] ; do
+       read -p "Is the DVD ready? (y/n)" ANSWER
+       if [ "$ANSWER" == "y" ] ; then
+               $RECORD_BIN -blank=fast
+               $RECORD_BIN -dao -eject -pad -tsize=$TSIZE -data $1 &
+               exit 0
+       elif [ "$ANSWER" == "n" ] ; then
+               EXIT=""
+               read -p "Do you really want to exit? (y/n)" EXIT
+               if [ "$EXIT" == "y" ] ; then
+                       exit 1
+               fi
+       fi
+done
diff --git a/examples/dump_on_cd_2/README b/examples/dump_on_cd_2/README
new file mode 100644 (file)
index 0000000..d4ed661
--- /dev/null
@@ -0,0 +1,12 @@
+[...]
+Since I modified the dump_on_cd scripts [...by adding the
+possibility to dump to DVD media...] and thereby 
+translated them to german, I attached them here.
+
+Furthermore, I think I improved the useability a bit.
+
+I hope you find them useful,
+
+Yours,
+
+Georg Lippold <g_lippold@sourceforge.net>
diff --git a/examples/dump_on_remote_cd/README b/examples/dump_on_remote_cd/README
new file mode 100644 (file)
index 0000000..d07761d
--- /dev/null
@@ -0,0 +1,35 @@
+> I'll be more than happy to put a copy of your scripts in the dump
+> distribution once you'll get this work :-)
+
+So you may have a look at the enclosed scripts.
+
+I use rsh in both directions. This may easily be changed to ssh.
+
+Basically three scripts are now necessary. The first wraps around the
+dump-command, the second acts as user exit when CD has to be changed
+and the third has to be run on the remote box.
+
+To make things easier I put the first two into one file called
+dump-to-remote-cd. The second file called get-dumpdata-to-cdrecord must
+be copied to the box with the CD-Burner. There is a small
+configuration section in it to get cdrecord to work.  
+
+dump-to-remote-cd may be called with the capacity of the media which
+is used and / or a filesystem argument passed to dump.
+
+Usage is: 
+
+dump-to-remote-cd [ -c <CD_capacity> ] [files to dump ...]
+
+There are defaults in the scripts which are used if any of these
+arguments are missing. The hostname of the box with the CD-burner
+has to be edited in any case.
+
+Kind regards
+
+Gerd
+
+------------------------------------------------------------------------
+Gerd Bavendiek                             Linux Laptop Users check out:
+bav@epost.de                               http://netenv.sourceforge.net
+------------------------------------------------------------------------
diff --git a/examples/dump_on_remote_cd/dump-to-remote-cd b/examples/dump_on_remote_cd/dump-to-remote-cd
new file mode 100755 (executable)
index 0000000..cefc321
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/bash
+#ident "@(#) dump-to-remote-cd Time-stamp: <02/05/06 15:12:29 bav> "
+#******************************************************************
+# dump-to-remote-cd
+#******************************************************************
+#                              Gerd Bavendiek bav@epost.de 02-05-02
+#
+# Script used to dump to a remote box with a CD-Burner. There is a
+# companion script called get-dumpdata-to-cdrecord.
+# 
+# Usage: dump-to-remote-cd [ -c <CD_capacity> ] [files to dump ...]
+#
+# If called without arguments, it will dump / assuming 650 MB Media on
+# host kiki (see DEFAULT_ below).
+#
+# You must be able to do an rsh as root to BURN_HOST and vice versa,
+# see get-dumpdata-to-cdrecord. You may use ssh instead.
+#------------------------------------------------------------------
+
+#--- Customize to fit your needs ----------------------------------
+
+PATH_TO_GET_DUMPDATA_TO_CDRECORD=/root/tools/get-dumpdata-to-cdrecord
+PATH_TO_XTERM=/usr/X11R6/bin/xterm
+
+FIFO_NAME=/tmp/get-dumpdata-to-cdrecord.fifo
+
+BURN_HOST=kiki
+
+DEFAULT_CD_CAPACITY=650
+DEFAULT_FS=/
+
+#--- End of customizing -------------------------------------------
+
+USER_EXIT=$0
+
+Usage(){
+echo >&2 "Usage: `basename $0` [ -c <CD_capacity> ] [files to dump ...]"
+  exit 1
+}
+
+if [ `id -u` != 0 ]; then 
+  echo "$0: ERROR: root priviledges are required ..."
+  exit 1
+fi
+
+# Check whether first argument is a named pipe
+if [ -p "$1" ]; then
+   # We are called internally either from ourselves or from dump 
+   FIFO_NAME=$1
+   num=$[$2+1]
+   tput bel;sleep 1; tput bel
+   echo "Insert next CD (number $num) ..."
+   read -p "CD number $num ready ? " Ans
+   DUMP_HOST=`uname -n`
+   rsh $BURN_HOST \
+   $PATH_TO_XTERM -hold -T "Dump_CD_number_$num" -cr red -fn 6x10 -e \
+   $PATH_TO_GET_DUMPDATA_TO_CDRECORD -d $DUMP_HOST -f $FIFO_NAME &
+   exit 0
+fi
+
+CD_CAPACITY=$DEFAULT_CD_CAPACITY
+FS=$DEFAULT_FS
+
+# We will reach this code only when not called internally
+while getopts "b:c:h" c; do
+  case $c in
+   c) # Media Capacity
+      CD_CAPACITY=$OPTARG
+      ;;
+   h) # help those who ask for help
+      Usage
+      ;;
+   '?') # any other switch
+      Usage
+      ;;
+  esac
+done
+
+shift `expr $OPTIND - 1`
+
+if [ -n "$*" ]; then FS="$*"; fi
+
+DumpLevel=0               # level 0 dump
+Label=`date -I`           # Take today's date as label, e.g. 2002-05-02
+
+eval Capacity=$(($CD_CAPACITY*1024))
+
+# Remove the fifo on the server and make a new one
+rm -f $FIFO_NAME; mkfifo $FIFO_NAME
+
+# Call user exit for the very first time, all further calls will be
+# done via dump
+$USER_EXIT $FIFO_NAME 0 
+sleep 2
+
+# Run dump
+dump -z -B$Capacity -F $USER_EXIT -$DumpLevel -L $Label -f $FIFO_NAME $FS
+
diff --git a/examples/dump_on_remote_cd/get-dumpdata-to-cdrecord b/examples/dump_on_remote_cd/get-dumpdata-to-cdrecord
new file mode 100755 (executable)
index 0000000..ef7f226
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/bash
+#ident "@(#) get-dumpdata-to-cdrecord Time-stamp: <02/05/06 13:49:28 bav> "
+#******************************************************************
+# get-dumpdata-to-cdrecord
+#******************************************************************
+#                              Gerd Bavendiek bav@epost.de 02-05-02
+#
+# This script runs on the box which has the CD-Burner. It starts an
+# rsh on the box where dump is started and feeds the data to
+# cdrecord. You should have copied it to
+# PATH_TO_GET_DUMPDATA_TO_CDRECORD, see script dump-to-remote-cd.
+# 
+# You definitely may wish to customize the cdrecords arguments below !
+#
+# If rsh is not appropiate for you, change to ssh.
+#------------------------------------------------------------------
+
+CDRECORD_TESTMODE=""             # This means: burn !
+###CDRECORD_TESTMODE="-dummy"       # and this: not really ...
+CDRECORD_DEVICE="1,0"            # Run cdrecord --scanbus if in doubt
+CDRECORD_SPEED=2                 # Speed of your burner
+CDRECORD_BUFFERSIZE=16m          # Buffersize in MByte
+
+#------------------------------------------------------------------
+Usage()
+{
+   echo >&2 "Usage: `basename $0` -d <dump_host> -f <fifo_name>"
+   exit 1
+}
+
+CDRECORD_ARGLIST="-v $CDRECORD_TESTMODE dev=$CDRECORD_DEVICE speed=$CDRECORD_SPEED fs=$CDRECORD_BUFFERSIZE"
+
+while getopts "d:f:h" c; do
+  case $c in
+   d) # the dump host
+      DUMP_HOST=$OPTARG
+      ;;
+   f) # name of the fifo cdrecord has to read the data from
+      FIFO_NAME=$OPTARG
+      ;;
+   h) # help those who ask for help
+      Usage
+      ;;
+   '?') # any other switch
+      Usage
+      ;;
+  esac
+done
+
+if [ -z "$DUMP_HOST" -o -z "$FIFO_NAME" ]; then Usage; fi
+
+rsh $DUMP_HOST dd if=$FIFO_NAME | cdrecord $CDRECORD_ARGLIST -eject -pad -data -
+if [ $? -ne 0 ]; then
+   echo $0: `date '+%T'`: ERROR: Check cdrecords messages
+   exit 1
+fi
+
+# Local Variables:
+# rcpbuf-todo: ("/[root@kiki]/root/tools")
+# End:
diff --git a/examples/encrypted_rmt/README b/examples/encrypted_rmt/README
new file mode 100644 (file)
index 0000000..12a95f5
--- /dev/null
@@ -0,0 +1,77 @@
+This is a set of changes to the Linux "rmt" utility
+to support transparent encryption.
+Data is encrypted before it is written to tape, and decrypted when read.
+We use no padding or salt, so the data size doesn't change.
+Tools that use rmt for remote tape access (such as dump, restore
+and tar) can manipulate encrypted data without modification.
+
+The symmetric cipher is currently hardwired as Blowfish.
+
+[...]
+
+Building ermt:
+- Ensure that openssl-0.9.7a or later is installed.
+- Configure and build the package, enabling ermt support:
+       ./configure --enable-ermt
+       make
+  This will build an extra binary: rmt/ermt, the encrypting version.
+  If ermt fails to link because EVP_CIPHER_CTX_set_padding
+  is undefined, you must upgrade to openssl-0.9.7a or later.
+
+Run-time setup:
+- Create a user for remote tape access, which we will call "dump":
+       useradd -m dump
+- ermt reads the secret key from ".ermt.key".
+  Generate a random key in ~dump/.ermt.key:
+       su - dump
+       openssl rand -out .ermt.key 32
+       chmod 400 .ermt.key
+  Due to the way "openssl enc -kfile $file" reads the key file,
+  you should ensure that the key contains no \0 or \r or \n characters,
+  which would prematurely truncate the key length.
+- Protect the key: copy to many floppies, "od -x .ermt.key|lpr", etc.
+- Set up rsh access from root (or whoever you run dump as)
+  to dump@localhost:
+       # still running as user dump here
+       echo localhost root > .rhosts
+       chmod 400 .rhosts
+  Or use ssh if you prefer; details left as an exercise.
+- Check that it works: run "rsh localhost -l dump date" as root.
+- Copy the ermt binary you built above to ~dump,
+  and change dump's shell to ~dump/ermt.
+
+Backup usage: just dump remotely to localhost:
+
+       dump -0u -f dump@localhost:/dev/st0 /
+       restore -i -f dump@localhost:/dev/st0
+       # You can use GNU tar too
+
+If your device is doing hardware compression, it's best to turn
+it off, since encrypted data compresses very poorly.
+
+Emergency decrypting: if you need to restore a tape and
+don't have access to a host running ermt,
+you have two choices:
+- If you have a copy of the ermt binary, run it with the -d switch
+  to decrypt stdin to stdout:
+       dd if=/dev/st0 bs=10k |
+       (cd ~dump; ./ermt -d) |         # assuming ermt is in ~dump
+       restore -i -f -
+- If not, use the OpenSSL "openssl" command, which does the same thing:
+       dd if=/dev/st0 bs=10k |
+        openssl enc -d -kfile ~dump/.ermt.key -blowfish -nosalt -nopad |
+       restore -i -f -
+  Versions of OpenSSL before 0.9.7a don't understand -nopad,
+  so they won't work.
+
+How much does encryption slow down backups?
+In my tests, the network hop is the bottleneck:
+dumping unencrypted (i.e. standard rmt) to localhost is 38%
+slower than dumping directly to tape.
+Adding encryption makes no difference, which isn't surprising.
+
+Change log:
+       2003-04-08: added configure --enable-ermt, separate ermt binary
+       2003-04-06: Initial release
+
+-- Ken Lalonde <ken@globalremit.com>
diff --git a/examples/howto/ultra-mini-howto b/examples/howto/ultra-mini-howto
new file mode 100644 (file)
index 0000000..a3628e5
--- /dev/null
@@ -0,0 +1,314 @@
+Dump/Restore Ultra-Mini-FAQ
+
+Document v1.1
+
+Disclaimer: I am not an expert in dump/restore.  In 
+fact, I'm a newbie.  But I've been picking things up as
+I implement it here and I wanted to pass some of those
+things along in the form of a very basic FAQ.
+
+-Patrick Walsh
+
+1) Introduction/ Non-rewinding device
+2) Dump command line
+3) Sending 2 or more filesystems to a tape
+4) Compressing dumps on the fly
+5) The "nodump" file and directory attribute.
+6) Restoring your dumps (including compressed).
+7) How to confirm a backup (highly recommended)
+8) What are the best buffer size options?
+9) Experiencing bread, lseek, lseek2 errors.
+10) Example backup script
+
+ 1) Introduction/ Non-rewinding device
+
+You use dump to backup to a file or a tape device.  If
+you're backing up to a tape device, then the first 
+thing you need to understand is that there are two 
+devices that refer to your tape drive.  There is the 
+"rewinding" device and the "non-rewinding" device.
+
+I wish I could tell you an easy way to figure out what
+your device names are, but I don't know one.  On my
+local box I had a /dev/tape device that linked to
+/dev/st0.  It turns out that /dev/st0 is my "rewinding"
+tape drive.  If I write to this device it will always
+rewind before starting to write.  This means that if
+you try to dump two filesystems, only the second one
+will be stored.  If your tape device is /dev/st0, like
+mine, then your non-rewinding tape device is probably
+/dev/nst0.
+
+Anyway, through the rest of this I will refer to $TAPE
+and $RWTAPE.  $TAPE is the non-rewinding device (in my
+case /dev/nst0) and $RWTAPE is the rewinding tape (in 
+my case /dev/st0 and /dev/tape).  $FS is the filesystem
+you are backing up, such as /dev/hda1.
+
+ 2) What options should I use?
+
+Use the man page to figure out what options to send
+to dump.  I use "dump 0uanf $TAPE $FS".
+
+  u=update /etc/dumpdates after a successful dump
+  a=auto-size -- bypass all tape length calculations 
+    and write until eof
+  n=notify 'operators' group when dump needs attention
+  f=backup to file or device specified, or - for stdout
+
+ 3) You want to send two or more filesystems to tape.
+
+OK, rewind using the mt command, then dump multiple
+times to the non-rewinding device, and you're done:
+
+mt -f $TAPE rewind
+dump 0uanf $TAPE $FS1
+dump 0uanf $TAPE $FS2
+etc.
+
+Check the man page of mt if you want to know how to
+eject the tape or retension it or anything.
+
+ 4) You want to compress your dumps on the fly.  No
+problem.  Send your backup to STDOUT and manipulate it
+from there.  It's easier if you're sending your output
+to the hard drive:
+
+dump 0uanf - $FS | gzip -c > /backup/outfile.dump.gz
+
+You want that to be written to the tape on the fly?  
+Try this:
+
+mt -f $TAPE rewind
+dump 0uanf - $FS |gzip -c |dd if=- of=$TAPE
+
+[ You can also use the -z or -J options of dump in the 
+  recent versions to enable internal compression - stelian ]
+
+ 5) You read the man page and you're wondering what the
+heck a "nodump" flag is.  For example, how can you get
+dump to stop backing up /tmp or ~/.netscape/cache.  You
+have two options: either exclude the inode in your dump
+command, or flag the files and directories with the
+"nodump" flag.  To flag /tmp, for example, do this:
+
+chattr -R +d /tmp
+
+Want more details?  Try 'man chattr' and 'man lsattr'.
+
+ 6) You want to know how to restore your backup.
+
+Read the restore man page.  But barring that, the easy 
+way is to use restore in interactive mode.  If you have
+three filesystems on one tape and you want to restore 
+files from the second one, you need to do this:
+
+mt -f $TAPE rewind
+mt -f $TAPE fsf 1     # skip forward one file
+restore -if $TAPE
+
+OK, suppose now that you used the commands in section 4
+to compress the dump file before it was written to 
+disk.  Use this command:
+
+mt -f $TAPE rewind
+mt -f $TAPE fsf 1
+dd if=$TAPE of=- |gzip -dc |restore -rf -
+
+Obviously if you dumped to a file instead of a tape it 
+is much easier:
+
+gzip -dc $filename |restore -rf -
+
+ 7) How to confirm your backup
+
+ Check out the restore man page and read up on the -C 
+option.
+
+ 8) What are the best buffer size options?
+  Bernhard R. Erdmann answered this question on the 
+dump-users mailing list.  His excellent response 
+follows:
+
+>> While I was doing google searches, there seems to be
+>> an issue regarding the default buffer size writing 
+>> to tape. According to some, the default buffer size 
+>> of 512 can harm modern drives.  I have a Seagate 
+>> DDS3 unit and am wondering what the best mt/dump 
+>> options are.  I am using datacompression in 
+>> hardware.  Should I go with a large buffer (mt 
+>> setblk 10240) or variable (mt setblk 0).  If I 
+>> change these sizes, does dump need to know about it?
+>
+>Dump/restore uses a default blocksize of 10 KB. You 
+>can change it with the "-b" option or use dd for 
+>(re-)blocking.
+>
+>dump 0ab 32 /
+>dump 0af - / | dd obs=32k of=$TAPE
+>ssh host "/sbin/dump 0af - /" | dd obs=32k of=$TAPE
+>restore rb 32
+>dd ibs=32k if=$TAPE | restore rf -
+>ssh host "dd if=/dev/nst0 ibs=32k" | restore rf -
+>
+>Personally, I'd stick with variable blocksize on the 
+>drive and use 32 KB as the application's blocksize as 
+>Amanda uses that size, too.
+>
+>Rumours told using 64 KB or 128 KB blocksize yields to
+>increase performance (maybe on the mtx list from an 
+>Arkeia developer) didn't had any effects in my own 
+>tests with blocksizes ranging from 10 to 64 KB some 
+>months ago on a DDS-2 drive.
+>
+>Regarding tape drive performance at different block 
+>sizes you may want to read 
+>http://www.rs6000.ibm.com/support/micro/tapewhdr.html#Header_133
+>
+>- Block size, can effect the time for backup/restore. 
+>Using large blocksizes may improve performance. Using 
+>small block sizes can increase system overhead but 
+>before changing to a large blocksize it is necessary 
+>to be sure the user application supports the larger 
+>blocksize chosen. 
+>- Very long restore times due to blocksize. If a 
+>backup is done with a fixed block length then the 
+>restore should be done with the same fixed block 
+>length. If a backup is done with a fixed block length 
+>and the restore is done with variable block length, 
+>the restore may work successfully but it may take many
+>more hours to restore than it took to back up the 
+>data. The reason for this is that when AIX reads fixed
+>block length data in variable block mode, a check 
+>condition is issued by the tape drive on every read. 
+>AIX must interpret every check condition and determine
+>the proper action to take. This often will put the 
+>tape drive into a mode of reading that will require 
+>the tape drive to stop tape motion, rewind the tape 
+>some distance, then start reading again. This will 
+>reduce the life expectancy of the tape and increase 
+>the time it takes to backup data.
+
+ 9) Experiencing bread, lseek, and lseek2 errors.
+  These errors are caused by inodes being changed
+during the backup.  This is normal because dump and
+the Linux kernel are both acessing the filesystem
+and there is no consistence checking. By "calming"
+the system (killing unnecessary processes), you 
+decrease the likelihood of having these
+errors.  Read up on the bug on Sourcefourge:
+
+http://sourceforge.net/tracker/index.php?func=detail&aid=204909&group_id=1306&atid=101306
+
+Note that the only "real" solution to this problem
+is to dump a unmounted filesystem or use a filesystem
+snapshot feature (like in LVM).
+
+ 10) That about sums up my knowledge on the matter, but
+I feel better having written something for other peopleto look at so it doesn't take them quite so long to 
+learn the things I did.  I've included my backup script
+below.  There are much better ones floating around, so 
+go find someone else's and use theirs if mine won't 
+work for you or you don't understand it.
+
+
+#!/bin/csh
+# System backup script for NARNIA
+
+# This is a script that will backup the entire hard drive
+# to the NT server (not my choice) \\fs1.
+#
+# On each Sunday night, a full backup will be made
+# of the hard drive and each day of the week thereafter an incremental
+# backup will be made that captures only those changes since the night
+# before.
+# Each full backup will be sent to the local tape as well as to the
+# NT machine.
+#
+# The files will be stored in partition-specific files with integer
+# endings that specify the day of the week they were saved.  Files
+# with zero on the end will always be full backups.
+
+# Dump options:
+#   a=auto-size -- bypass all tape length calculations and write until eof
+#   f=write the backup to file or device specified or - for stdout
+#   n=notify operators group when dump needs attention
+#   u=update /etc/dumpdates after a successful dump
+
+# Set variables that control the script.
+setenv MOUNTPOINT '/root/fs1backup'
+setenv OUTDIR '/root/fs1backup/narnia'
+setenv TAPE '/dev/nst0'  # non-rewinding tape
+
+# Auto-set variable that determines level of backup.
+setenv DAY `date +'%w'`
+
+# Mount the backup partition to /root/fs1backup
+/usr/bin/smbmount \\\\fs1\\backup $MOUNTPOINT -o
+"username=uname,password=pword"
+
+# Delete files created on this day last week
+rm -f $OUTDIR/*$DAY.dump.gz
+
+# Do the actual backing up, one filesystem at a time.
+
+# /dev/hda1 = /boot
+/sbin/dump $DAY'uanf' - /dev/hda1 | gzip -c >$OUTDIR/boot-$DAY.dump.gz
+
+# /dev/hda2 = /
+/sbin/dump $DAY'uanf' - /dev/hda2 | gzip -c >$OUTDIR/root-$DAY.dump.gz
+
+# /dev/hda3 = /usr
+/sbin/dump $DAY'uanf' - /dev/hda3 | gzip -c >$OUTDIR/usr-$DAY.dump.gz
+
+# /dev/hdb2 = /u1
+/sbin/dump $DAY'uanf' - /dev/hdb2 | gzip -c >$OUTDIR/u1-$DAY.dump.gz
+
+
+# OK, presumably everything is now backed up to \\fs1. On level 0
+# dumps, lets backup to the local drive too.
+if ($DAY == 0) then
+ mt -f $TAPE retension
+ foreach i ($OUTDIR/*0.dump.gz)
+  dd if=$i of=$TAPE
+ end
+ mt -f $TAPE rewind
+endif
+
+
+# Unmount the backup partition, not needed outside of script
+umount /root/fs1backup
+
+# Explicitly free up the temporary variables
+unsetenv DAY
+unsetenv MOUNTPOINT
+unsetenv OUTDIR
+unsetenv TAPE
+
+
+# RESTORE DIRECTIONS:
+# If from tape:
+#    dd if=$TAPE of=- | gzip -dc | restore -rf -
+# or dd if=$TAPE |gzip -dc |restore -rf -
+#
+# Note: must queue tape to proper position first.  This
+# is done by first rewinding then advancing to the proper
+# file.  The order that files are written to tape is
+# *probably* 0=/boot 1=/ 2=/usr 3=/u1
+#
+# Use mt to skip between them:
+#  mt -f $TAPE rewind
+# restore -if $TAPE   #now restoring /boot, probably
+# mt -f $TAPE fsf 1
+# restore -if $TAPE   #now restoring /
+# mt -f $TAPE fsf 1
+# restore -if $TAPE   #now restoring /usr
+# #etc.
+#
+# Otherwise:
+#    gzip -dc $filename | restore -rf -
+
+
+
diff --git a/examples/remote_backup_ssh/backitup b/examples/remote_backup_ssh/backitup
new file mode 100644 (file)
index 0000000..eacdd3b
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+#
+# This script will backup local drives to a remote tape drive over ssh.
+#  written by David B. Peterson <dave@toppledwagon.com>
+#
+# Follow these steps before using it the first time:
+# 1.  Configure the env variables below, especially OPERATOR, TAPEHOST
+#      TAPEDEV, and FILESYSTEMS
+# 2.  run the following commands as root (on the machine to be backed up):
+# ssh-keygen -t dsa
+# cat ~/.ssh/id_dsa.pub | ssh OPERATOR@TAPEHOST 'cat - >> ~/.ssh/authorized_keys2'
+#
+# where OPERATOR and TAPEHOST are as you have defined below.
+
+# We will run under screen so you can come back to the backup, if you need to.
+if [ ! "$WINDOW" ]; then
+   exec screen $0
+   exit
+fi
+
+# ssh-agent allows us to backup securely without entering the passphrase so
+# many times.  This version uses openssh v2.9
+if [ ! $SSH_AGENT_PID ]; then
+   echo Starting ssh-agent...
+   exec ssh-agent -- /bin/sh $0
+   exit
+fi
+
+OPERATOR=backup
+TAPEHOST=tapehost.example.com
+TAPEDEV=/dev/nst0
+RMT=/sbin/rmt
+RSH='/usr/bin/ssh'
+DATE=`date +%Y%m%d`
+DUMP='/sbin/dump 0auf'
+LOGDIR=/var/log/backup
+FILESYSTEMS='hda1 hda7 hda6 hda5 hda10'
+
+#### config above ####
+# backup FILESYSTEMS to the TAPEDEV on TAPEHOST with DUMP as OPERATOR using RSH
+
+export RMT RSH
+mkdir -p $LOGDIR &> /dev/null
+ssh-add ~/.ssh/id_dsa
+
+echo "Rewinding tape..."
+REWIND="mt -f $TAPEDEV rewind"
+$RSH $OPERATOR@$TAPEHOST $REWIND
+
+for FS in $FILESYSTEMS
+do
+   $DUMP $OPERATOR@$TAPEHOST:$TAPEDEV /dev/$FS 2>&1 | tee $LOGDIR/$FS.$DATE
+done
+
+echo "Rewinding and ejecting tape..."
+OFFLINE="mt -f $TAPEDEV offline"
+$RSH $OPERATOR@$TAPEHOST $OFFLINE
+
diff --git a/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..11870f1
--- /dev/null
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, 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 name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       :
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+               chmodcmd=""
+       else
+               instcmd=$mkdirprog
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f "$src" ] || [ -d "$src" ]
+       then
+               :
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               :
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               :
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+       '
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               :
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               :
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/linux-1.2.x.patch b/linux-1.2.x.patch
new file mode 100644 (file)
index 0000000..a313a0c
--- /dev/null
@@ -0,0 +1,17 @@
+--- fs/read_write.c.orig       Sun Aug 27 15:41:29 1995
++++ fs/read_write.c    Sun Aug 27 15:42:39 1995
+@@ -112,9 +112,11 @@
+       }
+       if (tmp < 0)
+               return -EINVAL;
+-      file->f_pos = tmp;
+-      file->f_reada = 0;
+-      file->f_version = ++event;
++      if (tmp != file->f_pos) {
++              file->f_pos = tmp;
++              file->f_reada = 0;
++              file->f_version = ++event;
++      }
+       memcpy_tofs(result, &file->f_pos, sizeof(loff_t));
+       return 0;
+ }
diff --git a/restore/Makefile.in b/restore/Makefile.in
new file mode 100644 (file)
index 0000000..cdc2004
--- /dev/null
@@ -0,0 +1,55 @@
+# $Id: Makefile.in,v 1.12 2003/05/08 21:11:39 stelian Exp $
+
+top_srcdir=    @top_srcdir@
+srcdir=                @srcdir@
+top_builddir=  ..
+
+@MCONFIG@
+
+INC=           -I$(top_srcdir)/restore
+ALL_CFLAGS=    @CPPFLAGS@ @CFLAGS@ @CCOPTS@ -pipe $(OPT) $(GINC) $(INC) $(DEFS) @RESTOREDEBUG@
+ALL_LDFLAGS=   @LDFLAGS@ @LDOPTS@ @STATIC@
+LIBS=          $(GLIBS) -le2p @READLINE@ @ZLIB@ @BZLIB@
+DEPLIBS=       ../compat/lib/libcompat.a
+
+PROG=          restore
+RPROG=         rrestore
+LINKS=         ${SBINDIR}/restore ${SBINDIR}/rrestore
+SRCS=          dirs.c interactive.c main.c restore.c symtab.c tape.c \
+               utilities.c
+OBJS=          dirs.o interactive.o main.o restore.o symtab.o tape.o \
+               utilities.o ../common/dumprmt.o
+MAN8=          restore.8
+RMAN8=         rrestore.8
+
+.c.o:
+       $(CC) -c $(ALL_CFLAGS) $< -o $@
+
+all::          $(PROG) $(MAN8)
+
+$(PROG):       $(OBJS) $(DEPLIBS)
+       $(CC) $(ALL_LDFLAGS) -o $(PROG) $(OBJS) $(LIBS)
+
+$(MAN8):       restore.8.in
+       sed -e "s|__DATE__|$(DATE)|g" \
+           -e "s|__VERSION__|$(VERSION)|g" $< > $@
+
+install::      all
+       $(INSTALL) -d $(SBINDIR) $(MANDIR)
+       $(INSTALLBIN) $(PROG) $(SBINDIR)
+       $(INSTALLMAN) $(MAN8) $(MANDIR)
+       cd $(SBINDIR) && $(RM) -f $(RPROG) && $(LN_S) $(PROG) $(RPROG)
+       cd $(MANDIR) && $(RM) -f $(RMAN8) && $(LN_S) $(MAN8) $(RMAN8)
+
+clean::
+       $(RM) -f $(PROG) $(MAN8) \#* *.s *.o *.a *~ core
+
+distclean::    clean
+       $(RM) -f Makefile Makefile.old .depend
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+
diff --git a/restore/dirs.c b/restore/dirs.c
new file mode 100644 (file)
index 0000000..2a23f94
--- /dev/null
@@ -0,0 +1,817 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: dirs.c,v 1.28 2004/05/25 10:39:30 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <compatlfs.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <bsdcompat.h>
+#else  /* __linux__ */
+#ifdef sunos
+#include <sys/fcntl.h>
+#include <bsdcompat.h>
+#else
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#endif
+#endif /* __linux__ */
+#include <protocols/dumprestore.h>
+
+#include <compaterr.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <endian.h>
+#else
+#ifdef sunos
+#include <arpa/nameser_compat.h>
+#else
+#include <machine/endian.h>
+#endif
+#endif
+
+#include "pathnames.h"
+#include "restore.h"
+#include "extern.h"
+
+/*
+ * Symbol table of directories read from tape.
+ */
+#define HASHSIZE       1000
+#define INOHASH(val) (val % HASHSIZE)
+struct inotab {
+       struct  inotab *t_next;
+       dump_ino_t t_ino;
+       OFF_T   t_seekpt;
+       OFF_T   t_size;
+};
+static struct inotab *inotab[HASHSIZE];
+
+/*
+ * Information retained about directories.
+ */
+struct modeinfo {
+       dump_ino_t ino;
+       struct timeval timep[2];
+       mode_t mode;
+       uid_t uid;
+       gid_t gid;
+       unsigned int flags;
+};
+
+/*
+ * Definitions for library routines operating on directories.
+ */
+#undef DIRBLKSIZ
+#define DIRBLKSIZ 1024
+struct rstdirdesc {
+       int     dd_fd;
+       int32_t dd_loc;
+       int32_t dd_size;
+       char    dd_buf[DIRBLKSIZ];
+};
+
+/*
+ * Global variables for this file.
+ */
+static OFF_T   seekpt;
+static FILE    *df, *mf;
+static RST_DIR *dirp;
+static char    dirfile[MAXPATHLEN] = "#";      /* No file */
+static char    modefile[MAXPATHLEN] = "#";     /* No file */
+static char    dot[2] = ".";                   /* So it can be modified */
+
+/*
+ * Format of old style directories.
+ */
+#define ODIRSIZ 14
+struct odirect {
+       u_short d_ino;
+       char    d_name[ODIRSIZ];
+};
+
+#if defined(__linux__) || defined(sunos)
+static struct inotab   *allocinotab __P((dump_ino_t, struct new_bsd_inode *, OFF_T));
+#else
+static struct inotab   *allocinotab __P((dump_ino_t, struct dinode *, OFF_T));
+#endif
+static void             dcvt __P((struct odirect *, struct direct *));
+static void             flushent __P((void));
+static struct inotab   *inotablookup __P((dump_ino_t));
+static RST_DIR         *opendirfile __P((const char *));
+static void             putdir __P((char *, size_t));
+static void             putent __P((struct direct *));
+static void            rst_seekdir __P((RST_DIR *, OFF_T, OFF_T));
+static OFF_T           rst_telldir __P((RST_DIR *));
+static struct direct   *searchdir __P((dump_ino_t, char *));
+
+#ifdef sunos
+extern int fdsmtc;
+#endif
+
+/*
+ *     Extract directory contents, building up a directory structure
+ *     on disk for extraction by name.
+ *     If genmode is requested, save mode, owner, and times for all
+ *     directories on the tape.
+ */
+void
+extractdirs(int genmode)
+{
+       int i;
+#if defined(__linux__) || defined(sunos)
+       struct new_bsd_inode *ip;
+#else
+       struct dinode *ip;
+#endif
+       struct inotab *itp;
+       struct direct nulldir;
+       int fd;
+
+       Vprintf(stdout, "Extract directories from tape\n");
+       (void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%ld", tmpdir,
+               (long)dumpdate);
+       if (command != 'r' && command != 'R') {
+               (void) strncat(dirfile, "-XXXXXX",
+                       sizeof(dirfile) - strlen(dirfile));
+               fd = MKSTEMP(dirfile);
+       } else
+               fd = OPEN(dirfile, O_RDWR|O_CREAT|O_EXCL, 0666);
+       if (fd == -1 || (df = fdopen(fd, "w")) == NULL) {
+               if (fd != -1)
+                       close(fd);
+               err(1, "cannot create directory temporary %s", dirfile);
+       }
+       if (genmode != 0) {
+               (void) snprintf(modefile, sizeof(modefile), "%s/rstmode%ld", tmpdir, (long)dumpdate);
+               if (command != 'r' && command != 'R') {
+                       (void) strncat(modefile, "-XXXXXX",
+                               sizeof(modefile) - strlen(modefile));
+                       fd = MKSTEMP(modefile);
+               } else
+                       fd = OPEN(modefile, O_RDWR|O_CREAT|O_EXCL, 0666);
+               if (fd == -1 || (mf = fdopen(fd, "w")) == NULL) {
+                       if (fd != -1)
+                               close(fd);
+                       err(1, "cannot create modefile %s", modefile);
+               }
+       }
+       nulldir.d_ino = 0;
+       nulldir.d_type = DT_DIR;
+       nulldir.d_namlen = 1;
+       nulldir.d_name[0] = '/';
+       nulldir.d_name[1] = '\0';
+       nulldir.d_reclen = DIRSIZ(0, &nulldir);
+       for (;;) {
+               curfile.name = "<directory file - name unknown>";
+               curfile.action = USING;
+               ip = curfile.dip;
+               if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) {
+                       if ( fclose(df) == EOF )
+                               err(1, "cannot write to file %s", dirfile);
+                       dirp = opendirfile(dirfile);
+                       if (dirp == NULL)
+                               warn("opendirfile");
+                       if (mf != NULL && fclose(mf) == EOF )
+                               err(1, "cannot write to file %s", dirfile);
+                       i = dirlookup(dot);
+                       if (i == 0)
+                               panic("Root directory is not on tape\n");
+                       return;
+               }
+               itp = allocinotab(curfile.ino, ip, seekpt);
+               getfile(putdir, xtrnull);
+               putent(&nulldir);
+               flushent();
+               itp->t_size = seekpt - itp->t_seekpt;
+       }
+}
+
+/*
+ * skip over all the directories on the tape
+ */
+void
+skipdirs(void)
+{
+
+       while (curfile.dip && (curfile.dip->di_mode & IFMT) == IFDIR) {
+               skipfile();
+       }
+}
+
+/*
+ *     Recursively find names and inumbers of all files in subtree
+ *     pname and pass them off to be processed.
+ */
+void
+treescan(char *pname, dump_ino_t ino, long (*todo) __P((char *, dump_ino_t, int)))
+{
+       struct inotab *itp;
+       struct direct *dp;
+       int namelen;
+       OFF_T bpt;
+       char locname[MAXPATHLEN + 1];
+
+       itp = inotablookup(ino);
+       if (itp == NULL) {
+               /*
+                * Pname is name of a simple file or an unchanged directory.
+                */
+               (void) (*todo)(pname, ino, LEAF);
+               return;
+       }
+       /*
+        * Pname is a dumped directory name.
+        */
+       if ((*todo)(pname, ino, NODE) == FAIL)
+               return;
+       /*
+        * begin search through the directory
+        * skipping over "." and ".."
+        */
+       namelen = snprintf(locname, sizeof(locname), "%s/", pname);
+       if (namelen >= (int)sizeof(locname))
+               namelen = sizeof(locname) - 1;
+       rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
+       dp = rst_readdir(dirp); /* "." */
+       if (dp != NULL && strcmp(dp->d_name, ".") == 0)
+               dp = rst_readdir(dirp); /* ".." */
+       else
+               fprintf(stderr, "Warning: `.' missing from directory %s\n",
+                       pname);
+       if (dp != NULL && strcmp(dp->d_name, "..") == 0)
+               dp = rst_readdir(dirp); /* first real entry */
+       else
+               fprintf(stderr, "Warning: `..' missing from directory %s\n",
+                       pname);
+       bpt = rst_telldir(dirp);
+       /*
+        * a zero inode signals end of directory
+        */
+       while (dp != NULL) {
+               locname[namelen] = '\0';
+               if (namelen + dp->d_namlen >= (int)sizeof(locname)) {
+                       fprintf(stderr, "%s%s: name exceeds %ld char\n",
+                               locname, dp->d_name, (long)sizeof(locname) - 1);
+               } else {
+                       (void) strncat(locname, dp->d_name, (int)dp->d_namlen);
+                       treescan(locname, dp->d_ino, todo);
+                       rst_seekdir(dirp, bpt, itp->t_seekpt);
+               }
+               dp = rst_readdir(dirp);
+               bpt = rst_telldir(dirp);
+       }
+}
+
+/*
+ * Lookup a pathname which is always assumed to start from the ROOTINO.
+ */
+struct direct *
+pathsearch(const char *pathname)
+{
+       dump_ino_t ino;
+       struct direct *dp;
+       char *path, *name, buffer[MAXPATHLEN];
+
+       strcpy(buffer, pathname);
+       path = buffer;
+       ino = ROOTINO;
+       while (*path == '/')
+               path++;
+       dp = NULL;
+#ifdef __linux__
+       while ((name = strsep(&path, "/")) != NULL && *name /* != NULL */) {
+#else
+       while ((name = strtok_r(NULL, "/", &path)) != NULL && *name /* != NULL */) {
+#endif
+               if ((dp = searchdir(ino, name)) == NULL)
+                       return (NULL);
+               ino = dp->d_ino;
+       }
+       return (dp);
+}
+
+/*
+ * Lookup the requested name in directory inum.
+ * Return its inode number if found, zero if it does not exist.
+ */
+static struct direct *
+searchdir(dump_ino_t inum, char *name)
+{
+       struct direct *dp;
+       struct inotab *itp;
+       int len;
+
+       itp = inotablookup(inum);
+       if (itp == NULL)
+               return (NULL);
+       rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
+       len = strlen(name);
+       do {
+               dp = rst_readdir(dirp);
+               if (dp == NULL)
+                       return (NULL);
+       } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0);
+       return (dp);
+}
+
+/*
+ * Put the directory entries in the directory file
+ */
+static void
+putdir(char *buf, size_t size)
+{
+       struct direct cvtbuf;
+       struct odirect *odp;
+       struct odirect *eodp;
+       struct direct *dp;
+       long loc, i;
+
+       if (cvtflag && !ufs2flag) {
+               eodp = (struct odirect *)&buf[size];
+               for (odp = (struct odirect *)buf; odp < eodp; odp++)
+                       if (odp->d_ino != 0) {
+                               dcvt(odp, &cvtbuf);
+                               putent(&cvtbuf);
+                       }
+       } else {
+               for (loc = 0; loc < (long)size; ) {
+                       dp = (struct direct *)(buf + loc);
+#ifdef DIRDEBUG
+                       printf ("reclen = %d, namlen = %d, type = %d\n",
+                               dp->d_reclen, dp->d_namlen, dp->d_type);
+#endif
+                       if (Bcvt)
+                               swabst((u_char *)"is", (u_char *) dp);
+                       if (oldinofmt && dp->d_ino != 0) {
+#                              if BYTE_ORDER == BIG_ENDIAN
+                                       if (Bcvt)
+                                               dp->d_namlen = dp->d_type;
+#                              else
+                                       if (!Bcvt)
+                                               dp->d_namlen = dp->d_type;
+#                              endif
+                               if (dp->d_namlen == 0 && dp->d_type != 0)
+                                       dp->d_namlen = dp->d_type;
+                               dp->d_type = DT_UNKNOWN;
+                       }
+#ifdef DIRDEBUG
+                       printf ("reclen = %d, namlen = %d, type = %d\n",
+                               dp->d_reclen, dp->d_namlen, dp->d_type);
+#endif
+                       i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
+                       if ((dp->d_reclen & 0x3) != 0 ||
+                           dp->d_reclen > i ||
+                           dp->d_reclen < DIRSIZ(0, dp)
+#if MAXNAMLEN < 255
+                           || dp->d_namlen > MAXNAMLEN
+#endif
+                           ) {
+                               Vprintf(stdout, "Mangled directory: ");
+                               if ((dp->d_reclen & 0x3) != 0)
+                                       Vprintf(stdout,
+                                          "reclen not multiple of 4 ");
+                               if (dp->d_reclen < DIRSIZ(0, dp))
+                                       Vprintf(stdout,
+                                          "reclen less than DIRSIZ (%d < %d) ",
+                                          dp->d_reclen, DIRSIZ(0, dp));
+#if MAXNAMLEN < 255
+                               if (dp->d_namlen > MAXNAMLEN)
+                                       Vprintf(stdout,
+                                          "reclen name too big (%d > %d) ",
+                                          dp->d_namlen, MAXNAMLEN);
+#endif
+                               Vprintf(stdout, "\n");
+                               loc += i;
+                               continue;
+                       }
+                       loc += dp->d_reclen;
+                       if (dp->d_ino != 0) {
+                               putent(dp);
+                       }
+               }
+       }
+}
+
+/*
+ * These variables are "local" to the following two functions.
+ */
+static char dirbuf[DIRBLKSIZ];
+static long dirloc = 0;
+static long prev = 0;
+
+/*
+ * add a new directory entry to a file.
+ */
+static void
+putent(struct direct *dp)
+{
+       dp->d_reclen = DIRSIZ(0, dp);
+       if (dirloc + dp->d_reclen > DIRBLKSIZ) {
+               ((struct direct *)(dirbuf + prev))->d_reclen =
+                   DIRBLKSIZ - prev;
+               if ( fwrite(dirbuf, 1, DIRBLKSIZ, df) != DIRBLKSIZ )
+                       err(1,"cannot write to file %s", dirfile);
+               dirloc = 0;
+       }
+       memmove(dirbuf + dirloc, dp, (size_t)dp->d_reclen);
+       prev = dirloc;
+       dirloc += dp->d_reclen;
+}
+
+/*
+ * flush out a directory that is finished.
+ */
+static void
+flushent(void)
+{
+       ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
+       if ( fwrite(dirbuf, (int)dirloc, 1, df) != 1 )
+               err(1, "cannot write to file %s", dirfile);
+       seekpt = FTELL(df);
+       if (seekpt == -1)
+               err(1, "cannot write to file %s", dirfile);
+       dirloc = 0;
+}
+
+static void
+dcvt(struct odirect *odp, struct direct *ndp)
+{
+
+       memset(ndp, 0, (size_t)(sizeof *ndp));
+       ndp->d_ino =  odp->d_ino;
+       ndp->d_type = DT_UNKNOWN;
+       (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
+       ndp->d_namlen = strlen(ndp->d_name);
+       ndp->d_reclen = DIRSIZ(0, ndp);
+}
+
+/*
+ * Seek to an entry in a directory.
+ * Only values returned by rst_telldir should be passed to rst_seekdir.
+ * This routine handles many directories in a single file.
+ * It takes the base of the directory in the file, plus
+ * the desired seek offset into it.
+ */
+static void
+rst_seekdir(RST_DIR *dirp, OFF_T loc, OFF_T base)
+{
+
+       if (loc == rst_telldir(dirp))
+               return;
+       loc -= base;
+       if (loc < 0)
+               fprintf(stderr, "bad seek pointer to rst_seekdir %lld\n", (long long int)loc);
+       (void) LSEEK(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET);
+       dirp->dd_loc = loc & (DIRBLKSIZ - 1);
+       if (dirp->dd_loc != 0)
+               dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
+}
+
+/*
+ * get next entry in a directory.
+ */
+struct direct *
+rst_readdir(RST_DIR *dirp)
+{
+       struct direct *dp;
+
+       for (;;) {
+               if (dirp->dd_loc == 0) {
+                       dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
+                           DIRBLKSIZ);
+                       if (dirp->dd_size <= 0) {
+                               Dprintf(stderr, "error reading directory\n");
+                               return (NULL);
+                       }
+               }
+               if (dirp->dd_loc >= dirp->dd_size) {
+                       dirp->dd_loc = 0;
+                       continue;
+               }
+               dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
+               if (dp->d_reclen == 0 ||
+                   dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
+                       Dprintf(stderr, "corrupted directory: bad reclen %d\n",
+                               dp->d_reclen);
+                       return (NULL);
+               }
+               dirp->dd_loc += dp->d_reclen;
+               if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0)
+                       return (NULL);
+               if (dp->d_ino >= maxino) {
+                       Dprintf(stderr, "corrupted directory: bad inum %d\n",
+                               dp->d_ino);
+                       continue;
+               }
+               return (dp);
+       }
+}
+
+/*
+ * Simulate the opening of a directory
+ */
+RST_DIR *
+rst_opendir(const char *name)
+{
+       struct inotab *itp;
+       RST_DIR *dirp;
+       dump_ino_t ino;
+
+       if ((ino = dirlookup(name)) > 0 &&
+           (itp = inotablookup(ino)) != NULL) {
+               dirp = opendirfile(dirfile);
+               rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
+               return (dirp);
+       }
+       return (NULL);
+}
+
+/*
+ * In our case, there is nothing to do when closing a directory.
+ */
+void
+rst_closedir(RST_DIR *dirp)
+{
+
+       (void)close(dirp->dd_fd);
+       free(dirp);
+       return;
+}
+
+/*
+ * Simulate finding the current offset in the directory.
+ */
+static OFF_T
+rst_telldir(RST_DIR *dirp)
+{
+       return ((OFF_T)LSEEK(dirp->dd_fd,
+               (OFF_T)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc);
+}
+
+/*
+ * Open a directory file.
+ */
+static RST_DIR *
+opendirfile(const char *name)
+{
+       RST_DIR *dirp;
+       int fd;
+
+       if ((fd = OPEN(name, O_RDONLY)) == -1)
+               return (NULL);
+       if ((dirp = malloc(sizeof(RST_DIR))) == NULL) {
+               (void)close(fd);
+               return (NULL);
+       }
+       dirp->dd_fd = fd;
+       dirp->dd_loc = 0;
+       return (dirp);
+}
+
+/*
+ * Set the mode, owner, and times for all new or changed directories
+ */
+void
+setdirmodes(int flags)
+{
+       FILE *mf;
+       struct modeinfo node;
+       struct entry *ep;
+       char *cp;
+
+       Vprintf(stdout, "Set directory mode, owner, and times.\n");
+       if (command == 'r' || command == 'R')
+               (void) snprintf(modefile, sizeof(modefile), "%s/rstmode%lu", tmpdir, (long)dumpdate);
+       if (modefile[0] == '#') {
+               panic("modefile not defined\n");
+               fprintf(stderr, "directory mode, owner, and times not set\n");
+               return;
+       }
+       mf = fopen(modefile, "r");
+       if (mf == NULL) {
+               warn("fopen");
+               fprintf(stderr, "cannot open mode file %s\n", modefile);
+               fprintf(stderr, "directory mode, owner, and times not set\n");
+               return;
+       }
+       clearerr(mf);
+       for (;;) {
+               (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
+               if (feof(mf))
+                       break;
+               ep = lookupino(node.ino);
+               if (command == 'i' || command == 'x') {
+                       if (ep == NULL)
+                               continue;
+                       if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) {
+                               ep->e_flags &= ~NEW;
+                               continue;
+                       }
+                       if ((flags & FORCE) == 0 &&
+                           node.ino == ROOTINO &&
+                           reply("set owner/mode for '.'") == FAIL)
+                               continue;
+               }
+               if (ep == NULL) {
+                       panic("cannot find directory inode %d\n", node.ino);
+               } else {
+                       cp = myname(ep);
+                       (void) chown(cp, node.uid, node.gid);
+                       (void) chmod(cp, node.mode);
+                       if (node.flags)
+#ifdef __linux__
+                               (void) fsetflags(cp, node.flags);
+#else
+#ifdef sunos
+#else
+                               (void) chflags(cp, node.flags);
+#endif
+#endif
+                       utimes(cp, node.timep);
+                       ep->e_flags &= ~NEW;
+               }
+       }
+       if (ferror(mf))
+               panic("error setting directory modes\n");
+       (void) fclose(mf);
+}
+
+/*
+ * Generate a literal copy of a directory.
+ */
+int
+genliteraldir(char *name, dump_ino_t ino)
+{
+       struct inotab *itp;
+       int ofile, dp, i, size;
+       char buf[BUFSIZ];
+
+       itp = inotablookup(ino);
+       if (itp == NULL)
+               panic("Cannot find directory inode %d named %s\n", ino, name);
+       if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
+               warn("%s: cannot create file\n", name);
+               return (FAIL);
+       }
+       rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
+       dp = dup(dirp->dd_fd);
+       for (i = itp->t_size; i > 0; i -= BUFSIZ) {
+               size = i < BUFSIZ ? i : BUFSIZ;
+               if (read(dp, buf, (int) size) == -1) {
+                       warnx("write error extracting inode %lu, name %s\n",
+                               (unsigned long)curfile.ino, curfile.name);
+                       err(1, "read");
+               }
+               if (!Nflag && write(ofile, buf, (int) size) == -1) {
+                       warnx("write error extracting inode %lu, name %s\n",
+                               (unsigned long)curfile.ino, curfile.name);
+                       err(1, "write");
+               }
+       }
+       (void) close(dp);
+       (void) close(ofile);
+       return (GOOD);
+}
+
+/*
+ * Determine the type of an inode
+ */
+int
+inodetype(dump_ino_t ino)
+{
+       struct inotab *itp;
+
+       itp = inotablookup(ino);
+       if (itp == NULL)
+               return (LEAF);
+       return (NODE);
+}
+
+/*
+ * Allocate and initialize a directory inode entry.
+ * If requested, save its pertinent mode, owner, and time info.
+ */
+static struct inotab *
+#if defined(__linux__) || defined(sunos)
+allocinotab(dump_ino_t ino, struct new_bsd_inode *dip, OFF_T seekpt)
+#else
+allocinotab(dump_ino_t ino, struct dinode *dip, OFF_T seekpt)
+#endif
+{
+       struct inotab   *itp;
+       struct modeinfo node;
+
+       itp = calloc(1, sizeof(struct inotab));
+       if (itp == NULL)
+               panic("no memory directory table\n");
+       itp->t_next = inotab[INOHASH(ino)];
+       inotab[INOHASH(ino)] = itp;
+       itp->t_ino = ino;
+       itp->t_seekpt = seekpt;
+       if (mf == NULL)
+               return (itp);
+       node.ino = ino;
+#if defined(__linux__) || defined(sunos)
+       node.timep[0].tv_sec = dip->di_atime.tv_sec;
+       node.timep[0].tv_usec = dip->di_atime.tv_usec;
+       node.timep[1].tv_sec = dip->di_mtime.tv_sec;
+       node.timep[1].tv_usec = dip->di_mtime.tv_usec;
+#else  /* __linux__  || sunos */
+       node.timep[0].tv_sec = dip->di_atime;
+       node.timep[0].tv_usec = dip->di_atimensec / 1000;
+       node.timep[1].tv_sec = dip->di_mtime;
+       node.timep[1].tv_usec = dip->di_mtimensec / 1000;
+#endif /* __linux__  || sunos */
+       node.mode = dip->di_mode;
+       node.flags = dip->di_flags;
+       node.uid = dip->di_uid;
+       node.gid = dip->di_gid;
+       if ( fwrite((char *)&node, 1, sizeof(struct modeinfo), mf) != sizeof(struct modeinfo) )
+               err(1,"cannot write to file %s", modefile);
+       return (itp);
+}
+
+/*
+ * Look up an inode in the table of directories
+ */
+static struct inotab *
+inotablookup(dump_ino_t ino)
+{
+       struct inotab *itp;
+
+       for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
+               if (itp->t_ino == ino)
+                       return (itp);
+       return (NULL);
+}
+
+/*
+ * Clean up and exit
+ */
+void
+cleanup(void)
+{
+       closemt();
+       if (modefile[0] != '#')
+               (void) unlink(modefile);
+       if (dirfile[0] != '#')
+               (void) unlink(dirfile);
+}
diff --git a/restore/extern.h b/restore/extern.h
new file mode 100644 (file)
index 0000000..e2702ed
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: extern.h,v 1.23 2003/10/26 16:05:48 stelian Exp $
+ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <compatlfs.h>
+#ifndef __P
+#include <sys/cdefs.h>
+#endif
+#ifdef DUMP_MACOSX
+#include "darwin.h"
+#endif
+
+struct entry   *addentry __P((char *, dump_ino_t, int));
+long            addfile __P((char *, dump_ino_t, int));
+int             addwhiteout __P((char *));
+void            badentry __P((struct entry *, const char *));
+void            canon __P((char *, char *, int));
+void            checkrestore __P((void));
+void            closemt __P((void));
+void            cleanup __P((void));
+void            comparefile __P((char *));
+void            compareleaves __P((void));
+void            createfiles __P((void));
+void            createleaves __P((char *));
+void            createlinks __P((void));
+long            deletefile __P((char *, dump_ino_t, int));
+void            deleteino __P((dump_ino_t));
+void            delwhiteout __P((struct entry *));
+dump_ino_t      dirlookup __P((const char *));
+void            dumpsymtable __P((char *, long));
+void            extractdirs __P((int));
+int             extractfile __P((struct entry *, int));
+void            findunreflinks __P((void));
+char           *flagvalues __P((struct entry *));
+void            freeentry __P((struct entry *));
+void            freename __P((char *));
+int             genliteraldir __P((char *, dump_ino_t));
+char           *gentempname __P((struct entry *));
+void            getfile __P((void (*)(char *, size_t), void (*)(char *, size_t)));
+void            getvol __P((long));
+void            initsymtable __P((char *));
+int             inodetype __P((dump_ino_t));
+int             linkit __P((char *, char *, int));
+struct entry   *lookupino __P((dump_ino_t));
+struct entry   *lookupname __P((char *));
+long            listfile __P((char *, dump_ino_t, int));
+dump_ino_t      lowerbnd __P((dump_ino_t));
+void            mktempname __P((struct entry *));
+void            moveentry __P((struct entry *, char *));
+void            msg __P((const char *, ...));
+char           *myname __P((struct entry *));
+void            newnode __P((struct entry *));
+void            newtapebuf __P((long));
+long            nodeupdates __P((char *, dump_ino_t, int));
+void            onintr __P((int));
+void            panic __P((const char *, ...));
+void            pathcheck __P((char *));
+struct direct  *pathsearch __P((const char *));
+void            printdumpinfo __P((void));
+void            printvolinfo __P((void));
+void            removeleaf __P((struct entry *));
+void            removenode __P((struct entry *));
+void            removeoldleaves __P((void));
+void            removeoldnodes __P((void));
+void            renameit __P((char *, char *));
+int             reply __P((const char *));
+void            resizemaps __P((dump_ino_t, dump_ino_t));
+RST_DIR                *rst_opendir __P((const char *));
+struct direct  *rst_readdir __P((RST_DIR *));
+void            rst_closedir __P((RST_DIR *dirp));
+void            runcmdshell __P((void));
+char           *savename __P((char *));
+void            setdirmodes __P((int));
+void            setinput __P((char *));
+void            setup __P((void));
+void            skipdirs __P((void));
+void            skipfile __P((void));
+void            skipmaps __P((void));
+void            swabst __P((u_char *, u_char *));
+void            treescan __P((char *, dump_ino_t, long (*)(char *, dump_ino_t, int)));
+dump_ino_t      upperbnd __P((dump_ino_t));
+long            verifyfile __P((char *, dump_ino_t, int));
+void            xtrnull __P((char *, size_t));
+
+/* From ../dump/dumprmt.c */
+void           rmtclose __P((void));
+int            rmthost __P((const char *));
+int            rmtioctl __P((int, int));
+int            rmtopen __P((const char *, const int));
+int            rmtread __P((const char *, int));
+OFF_T          rmtseek __P((OFF_T, int));
+
+/* From e2fsprogs */
+int fsetflags __P((const char *, unsigned long));
+int fgetflags __P((const char *, unsigned long *));
+int setflags __P((int, unsigned long));
+
+#ifdef USE_QFA
+int    Inode2Tapepos __P((dump_ino_t, long *, long long *, int));
+int    GetTapePos __P((long long *));
+int    GotoTapePos __P((long long));
+void   ReReadFromTape __P((void));
+void   ReReadInodeFromTape __P((dump_ino_t));
+void    GetPathFile __P((char *, char *, char *));
+
+#ifdef sunos
+int            GetSCSIIDFromPath __P((char *, long *));
+int            OpenSMTCmt(char *);
+#endif
+#endif
+void   RequestVol __P((long));
+
+#ifdef DUMP_MACOSX
+int    extractfinderinfoufs __P((char *));
+int    extractresourceufs __P((char *));
+int    CreateAppleDoubleFileRes __P((char *, FndrFileInfo *, mode_t, int, struct timeval *, u_int32_t, u_int32_t));
+#endif
+
+
+
diff --git a/restore/interactive.c b/restore/interactive.c
new file mode 100644 (file)
index 0000000..ecbffda
--- /dev/null
@@ -0,0 +1,1042 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*
+ * Copyright (c) 1985, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: interactive.c,v 1.27 2003/10/26 16:05:48 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <bsdcompat.h>
+#else  /* __linux__ */
+#ifdef sunos
+#include <sys/fcntl.h>
+#include <bsdcompat.h>
+#else
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#endif
+#endif /* __linux__ */
+#include <protocols/dumprestore.h>
+
+#include <setjmp.h>
+#include <compaterr.h>
+#include <errno.h>
+#include <compatglob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#if defined(__linux__) || defined(sunos)
+extern char * __progname;
+#endif
+
+#include "restore.h"
+#include "extern.h"
+
+#if HAVE_READLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+
+static char *rl_gets (char *prompt);
+static void initialize_readline(void);
+static char **restore_completion (const char *text, int start, int end);
+static char *command_generator(const char *text, int state);
+static char *filename_generator(const char *text, int state);
+#endif
+
+#define round(a, b) (((a) + (b) - 1) / (b) * (b))
+
+/*
+ * Things to handle interruptions.
+ */
+static int runshell;
+static jmp_buf reset;
+static char *nextarg = NULL;
+static int pflag = 0;          /* prompt mode */
+/*
+ * Structure and routines associated with listing directories.
+ */
+struct afile {
+       dump_ino_t fnum;        /* inode number of file */
+       char    *fname;         /* file name */
+       short   len;            /* name length */
+       char    prefix;         /* prefix character */
+       char    postfix;        /* postfix character */
+};
+struct arglist {
+       int     freeglob;       /* glob structure needs to be freed */
+       int     argcnt;         /* next globbed argument to return */
+       glob_t  glob;           /* globbing information */
+       char    *cmd;           /* the current command */
+};
+
+static char    *copynext __P((char *, char *));
+static int      fcmp __P((const void *, const void *));
+static void     formatf __P((struct afile *, int));
+static void     getcmd __P((char *, char *, char *, int, struct arglist *));
+struct dirent  *glob_readdir __P((RST_DIR *dirp));
+static int      glob_stat __P((const char *, struct stat *));
+static void     mkentry __P((char *, struct direct *, struct afile *));
+static void     printlist __P((char *, char *));
+
+/*
+ * Read and execute commands from the terminal.
+ */
+void
+runcmdshell(void)
+{
+       struct entry *np;
+       dump_ino_t ino;
+       struct arglist arglist;
+       char curdir[MAXPATHLEN];
+       char name[MAXPATHLEN];
+       char cmd[BUFSIZ];
+
+#if HAVE_READLINE
+       initialize_readline();
+#endif
+       arglist.freeglob = 0;
+       arglist.argcnt = 0;
+       arglist.glob.gl_flags = GLOB_ALTDIRFUNC;
+       arglist.glob.gl_opendir = (void *)rst_opendir;
+       arglist.glob.gl_readdir = (void *)glob_readdir;
+       arglist.glob.gl_closedir = (void *)rst_closedir;
+       arglist.glob.gl_lstat = (int (*)(const char *, void *))glob_stat;
+       arglist.glob.gl_stat = (int (*)(const char *, void *))glob_stat;
+       canon("/", curdir, sizeof(curdir));
+loop:
+       if (setjmp(reset) != 0) {
+               if (arglist.freeglob != 0) {
+                       arglist.freeglob = 0;
+                       arglist.argcnt = 0;
+                       globfree(&arglist.glob);
+               }
+               nextarg = NULL;
+               volno = 0;
+       }
+       runshell = 1;
+       getcmd(curdir, cmd, name, sizeof(name), &arglist);
+       switch (cmd[0]) {
+       /*
+        * Add elements to the extraction list.
+        */
+       case 'a':
+               if (strncmp(cmd, "add", strlen(cmd)) != 0)
+                       goto bad;
+               ino = dirlookup(name);
+               if (ino == 0)
+                       break;
+               if (mflag)
+                       pathcheck(name);
+               treescan(name, ino, addfile);
+               break;
+       /*
+        * Change working directory.
+        */
+       case 'c':
+               if (strncmp(cmd, "cd", strlen(cmd)) != 0)
+                       goto bad;
+               ino = dirlookup(name);
+               if (ino == 0)
+                       break;
+               if (inodetype(ino) == LEAF) {
+                       fprintf(stderr, "%s: not a directory\n", name);
+                       break;
+               }
+               (void) strncpy(curdir, name, sizeof(curdir));
+               curdir[sizeof(curdir) - 1] = '\0';
+               break;
+       /*
+        * Delete elements from the extraction list.
+        */
+       case 'd':
+               if (strncmp(cmd, "delete", strlen(cmd)) != 0)
+                       goto bad;
+               np = lookupname(name);
+               if (np == NULL || (np->e_flags & NEW) == 0) {
+                       fprintf(stderr, "%s: not on extraction list\n", name);
+                       break;
+               }
+               treescan(name, np->e_ino, deletefile);
+               break;
+       /*
+        * Extract the requested list.
+        */
+       case 'e':
+               if (strncmp(cmd, "extract", strlen(cmd)) != 0)
+                       goto bad;
+               createfiles();
+               createlinks();
+               setdirmodes(oflag ? FORCE : 0);
+               if (dflag)
+                       checkrestore();
+               volno = 0;
+               break;
+       /*
+        * List available commands.
+        */
+       case 'h':
+               if (strncmp(cmd, "help", strlen(cmd)) != 0)
+                       goto bad;
+       case '?':
+               fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+                       "Available commands are:\n",
+                       "\tls [arg] - list directory\n",
+                       "\tcd arg - change directory\n",
+                       "\tpwd - print current directory\n",
+                       "\tadd [arg] - add `arg' to list of",
+                       " files to be extracted\n",
+                       "\tdelete [arg] - delete `arg' from",
+                       " list of files to be extracted\n",
+                       "\textract - extract requested files\n",
+                       "\tsetmodes - set modes of requested directories\n",
+                       "\tquit - immediately exit program\n",
+                       "\twhat - list dump header information\n",
+                       "\tverbose - toggle verbose flag",
+                       " (useful with ``ls'')\n",
+                       "\tprompt - toggle the prompt display\n",
+                       "\thelp or `?' - print this list\n",
+                       "If no `arg' is supplied, the current",
+                       " directory is used\n");
+               break;
+       /*
+        * List a directory.
+        */
+       case 'l':
+               if (strncmp(cmd, "ls", strlen(cmd)) != 0)
+                       goto bad;
+               printlist(name, curdir);
+               break;
+       /*
+        * Print current directory.
+        */
+       case 'p':
+               if (strncmp(cmd, "pwd", strlen(cmd)) == 0) {
+                       if (curdir[1] == '\0')
+                               fprintf(stderr, "/\n");
+                       else
+                               fprintf(stderr, "%s\n", &curdir[1]);
+               }
+       /*
+        * Toggle prompt mode.
+        */
+               else if (strncmp(cmd, "prompt", strlen(cmd)) == 0) {
+                       if (pflag) {
+                               fprintf(stderr, "prompt mode off\n");
+                               pflag = 0;
+                               break;
+                       }
+                       fprintf(stderr, "prompt mode on\n");
+                       pflag++;
+                       break;
+               }
+               else goto bad;
+               break;
+       /*
+        * Quit.
+        */
+       case 'q':
+               if (strncmp(cmd, "quit", strlen(cmd)) != 0)
+                       goto bad;
+               return;
+       case 'x':
+               if (strncmp(cmd, "xit", strlen(cmd)) != 0)
+                       goto bad;
+               return;
+       /*
+        * Toggle verbose mode.
+        */
+       case 'v':
+               if (strncmp(cmd, "verbose", strlen(cmd)) != 0)
+                       goto bad;
+               if (vflag) {
+                       fprintf(stderr, "verbose mode off\n");
+                       vflag = 0;
+                       break;
+               }
+               fprintf(stderr, "verbose mode on\n");
+               vflag++;
+               break;
+       /*
+        * Just restore requested directory modes.
+        */
+       case 's':
+               if (strncmp(cmd, "setmodes", strlen(cmd)) != 0)
+                       goto bad;
+               setdirmodes(FORCE);
+               break;
+       /*
+        * Print out dump header information.
+        */
+       case 'w':
+               if (strncmp(cmd, "what", strlen(cmd)) != 0)
+                       goto bad;
+               printdumpinfo();
+               printvolinfo();
+               break;
+       /*
+        * Turn on debugging.
+        */
+       case 'D':
+               if (strncmp(cmd, "Debug", strlen(cmd)) != 0)
+                       goto bad;
+               if (dflag) {
+                       fprintf(stderr, "debugging mode off\n");
+                       dflag = 0;
+                       break;
+               }
+               fprintf(stderr, "debugging mode on\n");
+               dflag++;
+               break;
+       /*
+        * Unknown command.
+        */
+       default:
+       bad:
+               fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
+               break;
+       }
+       goto loop;
+}
+
+/*
+ * Read and parse an interactive command.
+ * The first word on the line is assigned to "cmd". If
+ * there are no arguments on the command line, then "curdir"
+ * is returned as the argument. If there are arguments
+ * on the line they are returned one at a time on each
+ * successive call to getcmd. Each argument is first assigned
+ * to "name". If it does not start with "/" the pathname in
+ * "curdir" is prepended to it. Finally "canon" is called to
+ * eliminate any embedded ".." components.
+ */
+static void
+getcmd(char *curdir, char *cmd, char *name, int size, struct arglist *ap)
+{
+       char *cp;
+       static char input[BUFSIZ];
+       char output[BUFSIZ];
+#      define rawname input    /* save space by reusing input buffer */
+
+       /*
+        * Check to see if still processing arguments.
+        */
+       if (ap->argcnt > 0)
+               goto retnext;
+       if (nextarg != NULL)
+               goto getnext;
+       /*
+        * Read a command line and trim off trailing white space.
+        */
+#if HAVE_READLINE
+       snprintf(input, BUFSIZ, "%s\n", rl_gets(curdir));
+#else
+       do      {
+               if (pflag)
+                       fprintf(stderr, "%s:%s:%s > ", 
+                               __progname,
+                               spcl.c_filesys, 
+                               curdir[1] ? &curdir[1] : "/");
+               else
+                       fprintf(stderr, "%s > ", __progname);
+               (void) fflush(stderr);
+               (void) fgets(input, BUFSIZ, terminal);
+       } while (!feof(terminal) && input[0] == '\n');
+       if (feof(terminal)) {
+               (void) strcpy(cmd, "quit");
+               return;
+       }
+#endif
+       for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
+               /* trim off trailing white space and newline */;
+       *++cp = '\0';
+       /*
+        * Copy the command into "cmd".
+        */
+       cp = copynext(input, cmd);
+       ap->cmd = cmd;
+       /*
+        * If no argument, use curdir as the default.
+        */
+       if (*cp == '\0') {
+               (void) strncpy(name, curdir, size);
+               name[size - 1] = '\0';
+               return;
+       }
+       nextarg = cp;
+       /*
+        * Find the next argument.
+        */
+getnext:
+       cp = copynext(nextarg, rawname);
+       if (*cp == '\0')
+               nextarg = NULL;
+       else
+               nextarg = cp;
+       /*
+        * If it is an absolute pathname, canonicalize it and return it.
+        */
+       if (rawname[0] == '/') {
+               canon(rawname, name, size);
+       } else {
+               /*
+                * For relative pathnames, prepend the current directory to
+                * it then canonicalize and return it.
+                */
+               snprintf(output, sizeof(output), "%s/%s", curdir, rawname);
+               canon(output, name, size);
+       }
+       if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0)
+               fprintf(stderr, "%s: out of memory\n", ap->cmd);
+       if (ap->glob.gl_pathc == 0)
+               return;
+       ap->freeglob = 1;
+       ap->argcnt = ap->glob.gl_pathc;
+
+retnext:
+       strncpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt], size);
+       name[size - 1] = '\0';
+       if (--ap->argcnt == 0) {
+               ap->freeglob = 0;
+               globfree(&ap->glob);
+       }
+#      undef rawname
+}
+
+/*
+ * Strip off the next token of the input.
+ */
+static char *
+copynext(char *input, char *output)
+{
+       char *cp, *bp;
+       char quote;
+
+       for (cp = input; *cp == ' ' || *cp == '\t'; cp++)
+               /* skip to argument */;
+       bp = output;
+       while (*cp != ' ' && *cp != '\t' && *cp != '\0') {
+               /*
+                * Handle back slashes.
+                */
+               if (*cp == '\\') {
+                       if (*++cp == '\0') {
+                               fprintf(stderr,
+                                       "command lines cannot be continued\n");
+                               continue;
+                       }
+                       *bp++ = *cp++;
+                       continue;
+               }
+               /*
+                * The usual unquoted case.
+                */
+               if (*cp != '\'' && *cp != '"') {
+                       *bp++ = *cp++;
+                       continue;
+               }
+               /*
+                * Handle single and double quotes.
+                */
+               quote = *cp++;
+               while (*cp != quote && *cp != '\0')
+                       *bp++ = *cp++;
+               if (*cp++ == '\0') {
+                       fprintf(stderr, "missing %c\n", quote);
+                       cp--;
+                       continue;
+               }
+       }
+       *bp = '\0';
+       return (cp);
+}
+
+/*
+ * Canonicalize file names to always start with ``./'' and
+ * remove any embedded "." and ".." components.
+ */
+void
+canon(char *rawname, char *canonname, int len)
+{
+       char *cp, *np;
+
+       if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
+               (void) strcpy(canonname, "");
+       else if (rawname[0] == '/')
+               (void) strcpy(canonname, ".");
+       else
+               (void) strcpy(canonname, "./");
+       if (strlen(canonname) + strlen(rawname) >= (unsigned)len)
+               errx(1, "canonname: not enough buffer space");
+               
+       (void) strcat(canonname, rawname);
+       /*
+        * Eliminate multiple and trailing '/'s
+        */
+       for (cp = np = canonname; *np != '\0'; cp++) {
+               *cp = *np++;
+               while (*cp == '/' && *np == '/')
+                       np++;
+       }
+       *cp = '\0';
+       if (*--cp == '/')
+               *cp = '\0';
+       /*
+        * Eliminate extraneous "." and ".." from pathnames.
+        */
+       for (np = canonname; *np != '\0'; ) {
+               np++;
+               cp = np;
+               while (*np != '/' && *np != '\0')
+                       np++;
+               if (np - cp == 1 && *cp == '.') {
+                       cp--;
+                       (void) strcpy(cp, np);
+                       np = cp;
+               }
+               if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
+                       cp--;
+                       while (cp > &canonname[1] && *--cp != '/')
+                               /* find beginning of name */;
+                       (void) strcpy(cp, np);
+                       np = cp;
+               }
+       }
+}
+
+/*
+ * Do an "ls" style listing of a directory
+ */
+static void
+printlist(char *name, char *basename)
+{
+       struct afile *fp, *list, *listp = NULL;
+       struct direct *dp;
+       struct afile single;
+       RST_DIR *dirp;
+       int entries, len, namelen;
+       char locname[MAXPATHLEN + 1];
+
+       dp = pathsearch(name);
+       if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) ||
+           (!vflag && dp->d_ino == WINO))
+               return;
+       if ((dirp = rst_opendir(name)) == NULL) {
+               entries = 1;
+               list = &single;
+               mkentry(name, dp, list);
+               len = strlen(basename) + 1;
+               if (strlen(name) - len > (unsigned)single.len) {
+                       freename(single.fname);
+                       single.fname = savename(&name[len]);
+                       single.len = strlen(single.fname);
+               }
+       } else {
+               entries = 0;
+               while ((dp = rst_readdir(dirp)))
+                       entries++;
+               rst_closedir(dirp);
+               list = (struct afile *)malloc(entries * sizeof(struct afile));
+               if (list == NULL) {
+                       fprintf(stderr, "ls: out of memory\n");
+                       return;
+               }
+               if ((dirp = rst_opendir(name)) == NULL)
+                       panic("directory reopen failed\n");
+               fprintf(stderr, "%s:\n", name);
+               entries = 0;
+               listp = list;
+               namelen = snprintf(locname, sizeof(locname), "%s/", name);
+               if (namelen >= (int)sizeof(locname))
+                       namelen = sizeof(locname) - 1;
+               while ((dp = rst_readdir(dirp))) {
+                       if (dp == NULL)
+                               break;
+                       if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)
+                               continue;
+                       if (!vflag && (dp->d_ino == WINO ||
+                            strcmp(dp->d_name, ".") == 0 ||
+                            strcmp(dp->d_name, "..") == 0))
+                               continue;
+                       locname[namelen] = '\0';
+                       if (namelen + strlen(dp->d_name) >= MAXPATHLEN) {
+                               fprintf(stderr, "%s%s: name exceeds %d char\n",
+                                       locname, dp->d_name, MAXPATHLEN);
+                       } else {
+                               (void) strncat(locname, dp->d_name,
+                                   (int)strlen(dp->d_name));
+                               mkentry(locname, dp, listp++);
+                               entries++;
+                       }
+               }
+               rst_closedir(dirp);
+               if (entries == 0) {
+                       fprintf(stderr, "\n");
+                       free(list);
+                       return;
+               }
+               qsort((char *)list, entries, sizeof(struct afile), fcmp);
+       }
+       formatf(list, entries);
+       if (dirp != NULL) {
+               for (fp = listp - 1; fp >= list; fp--)
+                       freename(fp->fname);
+               fprintf(stderr, "\n");
+               free(list);
+       }
+}
+
+/*
+ * Read the contents of a directory.
+ */
+static void
+mkentry(char *name, struct direct *dp, struct afile *fp)
+{
+       char *cp;
+       struct entry *np;
+
+       fp->fnum = dp->d_ino;
+       fp->fname = savename(dp->d_name);
+       for (cp = fp->fname; *cp; cp++)
+               if (!vflag && (*cp < ' ' || *cp >= 0177))
+                       *cp = '?';
+       fp->len = cp - fp->fname;
+       if (dflag && TSTINO(fp->fnum, dumpmap) == 0)
+               fp->prefix = '^';
+       else if ((np = lookupname(name)) != NULL && (np->e_flags & NEW))
+               fp->prefix = '*';
+       else
+               fp->prefix = ' ';
+       switch(dp->d_type) {
+
+       default:
+               fprintf(stderr, "Warning: undefined file type %d\n",
+                   dp->d_type);
+               /* fall through */
+       case DT_REG:
+               fp->postfix = ' ';
+               break;
+
+       case DT_LNK:
+               fp->postfix = '@';
+               break;
+
+       case DT_FIFO:
+       case DT_SOCK:
+               fp->postfix = '=';
+               break;
+
+       case DT_CHR:
+       case DT_BLK:
+               fp->postfix = '#';
+               break;
+
+#ifndef __linux__
+       /* no need for this */
+       case DT_WHT:
+               fp->postfix = '%';
+               break;
+#endif
+
+       case DT_UNKNOWN:
+       case DT_DIR:
+               if (inodetype(dp->d_ino) == NODE)
+                       fp->postfix = '/';
+               else
+                       fp->postfix = ' ';
+               break;
+       }
+       return;
+}
+
+/*
+ * Print out a pretty listing of a directory
+ */
+static void
+formatf(struct afile *list, int nentry)
+{
+       struct afile *fp, *endlist;
+       int width, bigino, haveprefix, havepostfix;
+       int i, j, w, precision = 0, columns, lines;
+
+       width = 0;
+       haveprefix = 0;
+       havepostfix = 0;
+       bigino = ROOTINO;
+       endlist = &list[nentry];
+       for (fp = &list[0]; fp < endlist; fp++) {
+               if (bigino < (int)fp->fnum)
+                       bigino = fp->fnum;
+               if (width < fp->len)
+                       width = fp->len;
+               if (fp->prefix != ' ')
+                       haveprefix = 1;
+               if (fp->postfix != ' ')
+                       havepostfix = 1;
+       }
+       if (haveprefix)
+               width++;
+       if (havepostfix)
+               width++;
+       if (vflag) {
+               for (precision = 0, i = bigino; i > 0; i /= 10)
+                       precision++;
+               width += precision + 1;
+       }
+       width++;
+       columns = 81 / width;
+       if (columns == 0)
+               columns = 1;
+       lines = (nentry + columns - 1) / columns;
+       for (i = 0; i < lines; i++) {
+               for (j = 0; j < columns; j++) {
+                       fp = &list[j * lines + i];
+                       if (vflag) {
+                               fprintf(stderr, "%*ld ", precision, (long)fp->fnum);
+                               fp->len += precision + 1;
+                       }
+                       if (haveprefix) {
+                               putc(fp->prefix, stderr);
+                               fp->len++;
+                       }
+                       fprintf(stderr, "%s", fp->fname);
+                       if (havepostfix) {
+                               putc(fp->postfix, stderr);
+                               fp->len++;
+                       }
+                       if (fp + lines >= endlist) {
+                               fprintf(stderr, "\n");
+                               break;
+                       }
+                       for (w = fp->len; w < width; w++)
+                               putc(' ', stderr);
+               }
+       }
+}
+
+/*
+ * Skip over directory entries that are not on the tape
+ *
+ * First have to get definition of a dirent.
+ *
+ * For Linux the dirent struct is now included from bsdcompat.h
+ */
+#ifndef        __linux__
+#undef DIRBLKSIZ
+#include <dirent.h>
+#undef d_ino
+#endif /* ! __linux__ */
+
+struct dirent *
+glob_readdir(RST_DIR *dirp)
+{
+       struct direct *dp;
+       static struct dirent adirent; 
+
+       while ((dp = rst_readdir(dirp)) != NULL) {
+               if (!vflag && dp->d_ino == WINO)
+                       continue;
+               if (dflag || TSTINO(dp->d_ino, dumpmap))
+                       break;
+       }
+       if (dp == NULL)
+               return (NULL);
+       adirent.d_fileno = dp->d_ino;
+       memmove(adirent.d_name, dp->d_name, dp->d_namlen + 1);
+       return (&adirent);
+}
+
+/*
+ * Return st_mode information in response to stat or lstat calls
+ */
+static int
+glob_stat(const char *name, struct stat *stp)
+{
+       struct direct *dp;
+       dp = pathsearch(name);
+       if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) ||
+           (!vflag && dp->d_ino == WINO))
+               return (-1);
+       if (inodetype(dp->d_ino) == NODE)
+               stp->st_mode = IFDIR;
+       else
+               stp->st_mode = IFREG;
+       return (0);
+}
+
+/*
+ * Comparison routine for qsort.
+ */
+static int
+fcmp(const void *f1, const void *f2)
+{
+       return (strcmp(((struct afile *)f1)->fname,
+           ((struct afile *)f2)->fname));
+}
+
+/*
+ * respond to interrupts
+ */
+void
+onintr(UNUSED(int signo))
+{
+       int save_errno = errno;
+
+       if (command == 'i' && runshell)
+               longjmp(reset, 1);
+       if (reply("restore interrupted, continue") == FAIL)
+               exit(1);
+       errno = save_errno;
+}
+
+
+#if HAVE_READLINE
+
+#if !HAVE_READLINE_RLCM
+#define rl_completion_matches completion_matches
+#endif
+
+/* A static variable for holding the line. */
+static char *line_read = NULL;
+
+static char completion_curdir[MAXPATHLEN];
+
+static char *commands[] = { 
+       "add ", "cd ", "delete ", "extract ", "help ", 
+       "? ", "ls ", "pwd ", "prompt ", "quit ", "xit ", 
+       "verbose ", "setmodes ", "what ", "Debug ",
+       NULL };
+
+static char *files = NULL;
+
+static char *
+rl_gets (char *dir)
+{
+       char *prompt;
+       int sz;
+
+       snprintf(completion_curdir, MAXPATHLEN, "%s", dir);
+       completion_curdir[MAXPATHLEN - 1] = '\0';
+
+       if (pflag) {
+               sz = 6 + strlen(__progname) + strlen(spcl.c_filesys) + strlen((completion_curdir + 1 ? completion_curdir + 1 : "/"));
+               prompt = (char *)malloc(sz);
+               if (!prompt)
+                       return NULL;
+               snprintf(prompt, sz, "%s:%s:%s > ", 
+                       __progname,
+                       spcl.c_filesys, 
+                       (completion_curdir + 1 ? completion_curdir + 1 : "/"));
+       }
+       else {
+               sz = 4 + strlen(__progname);
+               prompt = (char *)malloc(sz);
+               if (!prompt)
+                       return NULL;
+               snprintf(prompt, sz, "%s > ", __progname);
+       }
+       prompt[sz - 1] = '\0';
+
+       if (line_read) {
+               free (line_read);
+               line_read = (char *)NULL;
+       }
+
+       do {
+               line_read = readline (prompt);
+       } while (line_read && !*line_read);
+
+       free(prompt);
+
+       if (!line_read) {
+               printf("\n");
+               return strdup("quit");
+       }
+
+       add_history (line_read);
+
+       return (line_read);
+}
+
+static char *
+command_generator(const char *text, int state)
+{
+       static int list_index, len;
+       char *name;
+
+       if (!state) {
+               list_index = 0;
+               len = strlen(text);
+       }
+
+       while ( (name = commands[list_index]) != NULL) {
+
+               list_index ++;
+
+               if (strncmp(name, text, len) == 0)
+                       return strdup(name);
+       }
+
+       return NULL;
+}
+
+static char *
+filename_generator(const char *text, int state)
+{
+       static int list_index;
+       char *name;
+       RST_DIR *dirp;
+       struct direct *dp;
+       static int entries;
+       char pname[MAXPATHLEN];
+       char fname[MAXPATHLEN];
+       char *slash;
+       char ppname[MAXPATHLEN];
+
+       if (!state) {
+               list_index = 0;
+
+               if (files != NULL) {
+                       free(files);
+                       entries = 0;
+                       files = NULL;
+               }
+               if ((slash = strrchr(text, '/')) != NULL) {
+                       int idx = slash - text;
+                       if (idx > MAXPATHLEN - 2)
+                               idx = MAXPATHLEN - 2;
+                       strncpy(ppname, text, MAXPATHLEN);
+                       ppname[MAXPATHLEN - 1] = '\0';
+                       ppname[idx] = '\0';
+                       if (text[0] == '/')
+                               snprintf(pname, MAXPATHLEN, ".%s", ppname);
+                       else
+                               snprintf(pname, MAXPATHLEN, "%s/%s", completion_curdir, ppname);
+                       strncpy(fname, ppname + idx + 1, MAXPATHLEN);
+                       ppname[idx] = '/';
+                       ppname[idx + 1] = '\0';
+               }
+               else {
+                       strncpy(pname, completion_curdir, MAXPATHLEN);
+                       strncpy(fname, text, MAXPATHLEN);
+                       ppname[0] = '\0';
+               }
+               pname[MAXPATHLEN - 1] = '\0';
+               fname[MAXPATHLEN - 1] = '\0';
+               if ((dirp = rst_opendir(pname)) == NULL)
+                       return NULL;
+               entries = 0;
+               while ((dp = rst_readdir(dirp)))
+                       entries++;
+               rst_closedir(dirp);
+               files = (char *)malloc(entries * MAXPATHLEN);
+               if (files == NULL) {
+                       fprintf(stderr, "Out of memory\n");
+                       entries = 0;
+                       return NULL;
+               }
+               if ((dirp = rst_opendir(pname)) == NULL)
+                       panic("directory reopen failed\n");
+               entries = 0;
+               while ((dp = rst_readdir(dirp))) {
+                        if (TSTINO(dp->d_ino, dumpmap) == 0)
+                                continue;
+                       if (strcmp(dp->d_name, ".") == 0 ||
+                           strcmp(dp->d_name, "..") == 0)
+                               continue;
+                       if (strncmp(dp->d_name, fname, strlen(fname)) == 0) {
+                               if (inodetype(dp->d_ino) == NODE)
+                                       snprintf(files + entries * MAXPATHLEN, MAXPATHLEN, "%s%s/", ppname, dp->d_name);
+                               else
+                                       snprintf(files + entries * MAXPATHLEN, MAXPATHLEN, "%s%s ", ppname, dp->d_name);
+                               *(files + (entries + 1) * MAXPATHLEN - 1) = '\0';
+                               ++entries;
+                       }
+                 }
+                 rst_closedir(dirp);
+       }
+
+       if (list_index >= entries)
+               return NULL;
+
+       name = strdup(files + list_index * MAXPATHLEN);
+       list_index ++;
+
+       return name;
+}
+
+static char **
+restore_completion (const char *text, int start, UNUSED(int end))
+{
+       char **matches;
+
+       if (start == 0)
+               matches = rl_completion_matches (text, command_generator);
+       else
+               matches = rl_completion_matches (text, filename_generator);
+
+       return (matches);
+}
+
+static void 
+initialize_readline(void) 
+{
+       rl_readline_name = "dump";
+       rl_attempted_completion_function = restore_completion;
+       rl_completion_entry_function = NULL;
+#if HAVE_READLINE_CAC  /* compile with readline 2.0 */
+       rl_completion_append_character = '\0';
+#endif
+       rl_instream = terminal;
+}
+
+#endif /* HAVE_READLINE */
diff --git a/restore/main.c b/restore/main.c
new file mode 100644 (file)
index 0000000..f53d740
--- /dev/null
@@ -0,0 +1,789 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: main.c,v 1.46 2004/04/13 13:04:33 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <compatlfs.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#ifdef __linux__
+#include <sys/time.h>
+#include <time.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <bsdcompat.h>
+#include <signal.h>
+#include <string.h>
+#else  /* __linux__ */
+#ifdef sunos
+#include <signal.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <bsdcompat.h>
+#include <sys/mtio.h>
+#else
+#include <ufs/ufs/dinode.h>
+#endif
+#endif /* __linux__ */
+#include <protocols/dumprestore.h>
+
+#include <compaterr.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#include <getopt.h>
+#endif
+
+#include "pathnames.h"
+#include "restore.h"
+#include "extern.h"
+
+int abortifconnerr = 1;                /* set to 1 if lib dumprmt.o should exit on connection errors
+                                otherwise just print a message using msg */
+
+int    aflag = 0, bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
+int    hflag = 1, mflag = 1, Mflag = 0, Nflag = 0, Vflag = 0, zflag = 0;
+int    uflag = 0, lflag = 0, Lflag = 0, oflag = 0;
+int    ufs2flag = 0;
+char   *Afile = NULL;
+int    dokerberos = 0;
+char   command = '\0';
+long   dumpnum = 1;
+long   volno = 0;
+long   ntrec;
+char   *dumpmap = NULL;
+char   *usedinomap = NULL;
+dump_ino_t maxino;
+time_t dumptime;
+time_t dumpdate;
+FILE   *terminal;
+char   *tmpdir;
+int    compare_ignore_not_found;
+int    compare_errors;
+char   filesys[NAMELEN];
+static const char *stdin_opt = NULL;
+char   *bot_script = NULL;
+dump_ino_t volinfo[TP_NINOS];
+
+#ifdef USE_QFA
+FILE   *gTapeposfp;
+char   *gTapeposfile;
+char   gTps[255];
+long   gSeekstart;
+int    tapeposflag;
+int    gTapeposfd;
+int    createtapeposflag;
+unsigned long qfadumpdate;
+long long curtapepos;
+#endif /* USE_QFA */
+
+long smtc_errno;
+
+#if defined(__linux__) || defined(sunos)
+char   *__progname;
+#endif
+
+static void obsolete __P((int *, char **[]));
+static void usage __P((void));
+static void use_stdin __P((const char *));
+
+#define FORCED_UMASK (077)
+
+int
+main(int argc, char *argv[])
+{
+       int ch;
+       dump_ino_t ino;
+       char *inputdev = _PATH_DEFTAPE;
+       char *symtbl = "./restoresymtable";
+       char *p, name[MAXPATHLEN];
+       FILE *filelist = NULL;
+       char fname[MAXPATHLEN];
+       mode_t orig_umask;
+#ifdef DEBUG_QFA
+       time_t tistart, tiend, titaken;
+#endif
+#ifdef USE_QFA
+       tapeposflag = 0;
+       createtapeposflag = 0;
+#endif /* USE_QFA */
+
+       /* Temp files should *not* be readable.  We set permissions later. */
+       orig_umask = umask(FORCED_UMASK);
+       filesys[0] = '\0';
+#if defined(__linux__) || defined(sunos)
+       __progname = argv[0];
+#endif
+
+       if (argc < 2)
+               usage();
+
+       if ((inputdev = getenv("TAPE")) == NULL)
+               inputdev = _PATH_DEFTAPE;
+       if ((tmpdir = getenv("TMPDIR")) == NULL)
+               tmpdir = _PATH_TMP;
+       if ((tmpdir = strdup(tmpdir)) == NULL)
+               err(1, "malloc tmpdir");
+       for (p = tmpdir + strlen(tmpdir) - 1; p >= tmpdir && *p == '/'; p--)
+               ;                                                               
+       obsolete(&argc, &argv);
+       while ((ch = getopt(argc, argv, 
+               "aA:b:CcdD:f:F:hi"
+#ifdef KERBEROS
+               "k"
+#endif
+               "lL:mMNo"
+#ifdef USE_QFA
+               "P:Q:"
+#endif
+               "Rrs:tT:uvVxX:y")) != -1)
+               switch(ch) {
+               case 'a':
+                       aflag = 1;
+                       break;
+               case 'A':
+                       Afile = optarg;
+                       aflag = 1;
+                       break;
+               case 'b':
+                       /* Change default tape blocksize. */
+                       bflag = 1;
+                       ntrec = strtol(optarg, &p, 10);
+                       if (*p)
+                               errx(1, "illegal blocksize -- %s", optarg);
+                       if (ntrec <= 0)
+                               errx(1, "block size must be greater than 0");
+                       break;
+               case 'c':
+                       cvtflag = 1;
+                       break;
+               case 'D':
+                       strncpy(filesys, optarg, NAMELEN);
+                       filesys[NAMELEN - 1] = '\0';
+                       break;
+               case 'T':
+                       tmpdir = optarg;
+                       break;
+               case 'd':
+                       dflag = 1;
+                       break;
+               case 'f':
+                       if( !strcmp(optarg,"-") )
+                               use_stdin("-f");
+                       inputdev = optarg;
+                       break;
+               case 'F':
+                       bot_script = optarg;
+                       break;
+               case 'h':
+                       hflag = 0;
+                       break;
+#ifdef KERBEROS
+               case 'k':
+                       dokerberos = 1;
+                       break;
+#endif
+               case 'C':
+               case 'i':
+#ifdef USE_QFA
+               case 'P':
+#endif
+               case 'R':
+               case 'r':
+               case 't':
+               case 'x':
+                       if (command != '\0')
+                               errx(1,
+                                   "%c and %c options are mutually exclusive",
+                                   ch, command);
+                       command = ch;
+#ifdef USE_QFA
+                       if (ch == 'P') {
+                               gTapeposfile = optarg;
+                               createtapeposflag = 1;
+                       }
+#endif
+
+                       break;
+               case 'l':
+                       lflag = 1;
+                       break;
+               case 'L':
+                       Lflag = strtol(optarg, &p, 10);
+                       if (*p)
+                               errx(1, "illegal limit -- %s", optarg);
+                       if (Lflag < 0)
+                               errx(1, "limit must be greater than 0");
+                       break;
+               case 'm':
+                       mflag = 0;
+                       break;
+               case 'M':
+                       Mflag = 1;
+                       break;
+               case 'N':
+                       Nflag = 1;
+                       break;
+               case 'o':
+                       oflag = 1;
+                       break;
+#ifdef USE_QFA
+               case 'Q':
+                       gTapeposfile = optarg;
+                       tapeposflag = 1;
+                       aflag = 1;
+                       break;
+#endif
+               case 's':
+                       /* Dumpnum (skip to) for multifile dump tapes. */
+                       dumpnum = strtol(optarg, &p, 10);
+                       if (*p)
+                               errx(1, "illegal dump number -- %s", optarg);
+                       if (dumpnum <= 0)
+                               errx(1, "dump number must be greater than 0");
+                       break;
+               case 'u':
+                       uflag = 1;
+                       break;
+               case 'v':
+                       vflag = 1;
+                       break;
+               case 'V':
+                       Vflag = 1;
+                       break;
+               case 'X':
+                       if( !strcmp(optarg,"-") ) {
+                               use_stdin("-X");
+                               filelist = stdin;
+                       }
+                       else
+                               if ( !(filelist = fopen(optarg,"r")) )
+                                       errx(1, "can't open file for reading -- %s", optarg);
+                       break;
+               case 'y':
+                       yflag = 1;
+                       break;
+               default:
+                       usage();
+               }
+       argc -= optind;
+       argv += optind;
+
+       if (command == '\0')
+               errx(1, "none of C, i, R, r, t or x options specified");
+
+#ifdef USE_QFA
+       if (!mflag && tapeposflag)
+               errx(1, "m and Q options are mutually exclusive");
+
+       if (tapeposflag && command != 'i' && command != 'x' && command != 't')
+               errx(1, "Q option is not valid for %c command", command);
+#endif
+       
+       if (Afile && command != 'i' && command != 'x' && command != 't')
+               errx(1, "A option is not valid for %c command", command);
+
+       if (signal(SIGINT, onintr) == SIG_IGN)
+               (void) signal(SIGINT, SIG_IGN);
+       if (signal(SIGTERM, onintr) == SIG_IGN)
+               (void) signal(SIGTERM, SIG_IGN);
+       setlinebuf(stderr);
+
+       atexit(cleanup);
+
+       if (command == 'C' && inputdev[0] != '/' && strcmp(inputdev, "-")
+#ifdef RRESTORE
+           && !strchr(inputdev, ':')
+#endif
+         ) {
+               /* since we chdir into the directory we are comparing
+                * to, we must retain the full tape path */
+               char wd[MAXPATHLEN], fullpathinput[MAXPATHLEN];
+               if (!getcwd(wd, MAXPATHLEN))
+                       err(1, "can't get current directory");
+               snprintf(fullpathinput, MAXPATHLEN, "%s/%s", wd, inputdev);
+               fullpathinput[MAXPATHLEN - 1] = '\0';
+               setinput(fullpathinput);
+       }
+       else
+               setinput(inputdev);
+
+       if (argc == 0 && !filelist) {
+               argc = 1;
+               *--argv = ".";
+       }
+
+#ifdef USE_QFA
+       if (tapeposflag) {
+               msg("reading QFA positions from %s\n", gTapeposfile);
+               if ((gTapeposfp = fopen(gTapeposfile, "r")) == NULL)
+                       errx(1, "can't open file for reading -- %s",
+                               gTapeposfile);
+               /* start reading header info */
+               if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
+                       errx(1, "not requested format of -- %s", gTapeposfile);
+               gTps[strlen(gTps) - 1] = 0;     /* delete end of line */
+               if (strcmp(gTps, QFA_MAGIC) != 0)
+                       errx(1, "not requested format of -- %s", gTapeposfile);
+               if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
+                       errx(1, "not requested format of -- %s", gTapeposfile);
+               gTps[strlen(gTps) - 1] = 0;
+               if (strcmp(gTps, QFA_VERSION) != 0)
+                       errx(1, "not requested format of -- %s", gTapeposfile);
+               /* read dumpdate */
+               if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
+                       errx(1, "not requested format of -- %s", gTapeposfile);
+               gTps[strlen(gTps) - 1] = 0;
+               qfadumpdate = atol(gTps);
+               /* read empty line */
+               if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
+                       errx(1, "not requested format of -- %s", gTapeposfile);
+               gTps[strlen(gTps) - 1] = 0;
+               /* read table header line */
+               if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL)
+                       errx(1, "not requested format of -- %s", gTapeposfile);
+               gTps[strlen(gTps) - 1] = 0;
+               /* end reading header info */
+               /* tape position table starts here */
+               gSeekstart = ftell(gTapeposfp); /* remember for later use */
+#ifdef sunos
+               if (GetSCSIIDFromPath(inputdev, &scsiid)) {
+                       errx(1, "can't get SCSI-ID for %s\n", inputdev);
+               }
+               if (scsiid < 0) {
+                       errx(1, "can't get SCSI-ID for %s\n", inputdev);
+               }
+               sprintf(smtcpath, "/dev/rsmtc%ld,0", scsiid);
+               if ((fdsmtc = open(smtcpath, O_RDWR)) == -1) {
+                       errx(1, "can't open smtc device: %s, %d\n", smtcpath, errno);
+               }
+#endif
+       }
+#endif /* USE_QFA */
+
+       switch (command) {
+       /*
+        * Compare contents of tape.
+        */
+       case 'C': {
+               struct STAT stbuf;
+
+               Vprintf(stdout, "Begin compare restore\n");
+               compare_ignore_not_found = 0;
+               compare_errors = 0;
+               setup();
+               printf("filesys = %s\n", filesys);
+               if (STAT(filesys, &stbuf) < 0)
+                       err(1, "cannot stat directory %s", filesys);
+               if (chdir(filesys) < 0)
+                       err(1, "cannot cd to %s", filesys);
+               compare_ignore_not_found = dumptime > 0;
+               initsymtable((char *)0);
+               extractdirs(0);
+               treescan(".", ROOTINO, nodeupdates);
+               compareleaves();
+               checkrestore();
+               if (compare_errors) {
+                       printf("Some files were modified!\n");
+                       exit(2);
+               }
+               break;
+       }
+
+       /*
+        * Interactive mode.
+        */
+       case 'i':
+               setup();
+               extractdirs(1);
+               initsymtable(NULL);
+               runcmdshell();
+               break;
+       /*
+        * Incremental restoration of a file system.
+        */
+       case 'r':
+               aflag = 1;      /* in -r or -R mode, -a is default */
+               setup();
+               if (dumptime > 0) {
+                       /*
+                        * This is an incremental dump tape.
+                        */
+                       Vprintf(stdout, "Begin incremental restore\n");
+                       initsymtable(symtbl);
+                       extractdirs(1);
+                       removeoldleaves();
+                       Vprintf(stdout, "Calculate node updates.\n");
+                       treescan(".", ROOTINO, nodeupdates);
+                       findunreflinks();
+                       removeoldnodes();
+               } else {
+                       /*
+                        * This is a level zero dump tape.
+                        */
+                       Vprintf(stdout, "Begin level 0 restore\n");
+                       initsymtable((char *)0);
+                       extractdirs(1);
+                       Vprintf(stdout, "Calculate extraction list.\n");
+                       treescan(".", ROOTINO, nodeupdates);
+               }
+               createleaves(symtbl);
+               createlinks();
+               setdirmodes(FORCE);
+               checkrestore();
+               if (dflag) {
+                       Vprintf(stdout, "Verify the directory structure\n");
+                       treescan(".", ROOTINO, verifyfile);
+               }
+               dumpsymtable(symtbl, (long)1);
+               break;
+       /*
+        * Resume an incremental file system restoration.
+        */
+       case 'R':
+               aflag = 1;      /* in -r or -R mode, -a is default */
+               initsymtable(symtbl);
+               skipmaps();
+               skipdirs();
+               createleaves(symtbl);
+               createlinks();
+               setdirmodes(FORCE);
+               checkrestore();
+               dumpsymtable(symtbl, (long)1);
+               break;
+       
+/* handle file names from either text file (-X) or the command line */
+#define NEXTFILE(p) \
+       p = NULL; \
+       if (argc) { \
+               --argc; \
+               p = *argv++; \
+       } \
+       else if (filelist) { \
+               if ((p = fgets(fname, MAXPATHLEN, filelist))) { \
+                       if ( *p && *(p + strlen(p) - 1) == '\n' ) /* possible null string */ \
+                               *(p + strlen(p) - 1) = '\0'; \
+                       if ( !*p ) /* skip empty lines */ \
+                               continue; \
+                       } \
+       }
+       
+       /*
+        * List contents of tape.
+        */
+       case 't':
+               setup();
+               extractdirs(0);
+               initsymtable((char *)0);
+               printvolinfo();
+               for (;;) {
+                       NEXTFILE(p);
+                       if (!p)
+                               break;
+                       canon(p, name, sizeof(name));
+                       ino = dirlookup(name);
+                       if (ino == 0)
+                               continue;
+                       treescan(name, ino, listfile);
+               }
+               break;
+       /*
+        * Batch extraction of tape contents.
+        */
+       case 'x':
+#ifdef DEBUG_QFA
+               tistart = time(NULL);
+#endif
+               setup();
+               extractdirs(1);
+               initsymtable((char *)0);
+               for (;;) {
+                       NEXTFILE(p);
+                       if (!p)
+                               break;
+                       canon(p, name, sizeof(name));
+                       ino = dirlookup(name);
+                       if (ino == 0)
+                               continue;
+                       if (mflag)
+                               pathcheck(name);
+                       treescan(name, ino, addfile);
+               }
+               createfiles();
+               createlinks();
+               setdirmodes(oflag ? FORCE : 0);
+               if (dflag)
+                       checkrestore();
+#ifdef sunos
+               if (fdsmtc != -1) {
+                       close(fdsmtc);
+               }
+#endif /* sunos */
+#ifdef DEBUG_QFA
+               tiend = time(NULL);
+               titaken = tiend - tistart;
+               msg("restore took %d:%02d:%02d\n", titaken / 3600, 
+                       (titaken % 3600) / 60, titaken % 60);
+#endif /* DEBUG_QFA */
+               break;
+#ifdef USE_QFA
+       case 'P':
+#ifdef DEBUG_QFA
+               tistart = time(NULL);
+#endif
+#ifdef sunos
+               if (GetSCSIIDFromPath(inputdev, &scsiid)) {
+                       errx(1, "can't get SCSI-ID for %s\n", inputdev);
+               }
+               if (scsiid < 0) {
+                       errx(1, "can't get SCSI-ID for %s\n", inputdev);
+               }
+               sprintf(smtcpath, "/dev/rsmtc%ld,0", scsiid);
+               if ((fdsmtc = open(smtcpath, O_RDWR)) == -1) {
+                       errx(1, "can't open smtc device: %s, %d\n", smtcpath, errno);
+               }
+#endif /* sunos */
+               setup();
+               msg("writing QFA positions to %s\n", gTapeposfile);
+               (void) umask(orig_umask);
+               if ((gTapeposfd = open(gTapeposfile, O_WRONLY|O_CREAT|O_TRUNC,
+                                      S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
+                                      |S_IROTH|S_IWOTH)) < 0)
+                       errx(1, "can't create tapeposfile\n");
+               (void) umask(FORCED_UMASK);
+               /* print QFA-file header */
+               sprintf(gTps, "%s\n%s\n%ld\n\n", QFA_MAGIC, QFA_VERSION, (unsigned long)spcl.c_date);
+               if (write(gTapeposfd, gTps, strlen(gTps)) != (ssize_t)strlen(gTps))
+                       errx(1, "can't write tapeposfile\n");
+               sprintf(gTps, "ino\ttapeno\ttapepos\n");
+               if (write(gTapeposfd, gTps, strlen(gTps)) != (ssize_t)strlen(gTps))
+                       errx(1, "can't write tapeposfile\n");
+
+               extractdirs(1);
+               initsymtable((char *)0);
+               for (;;) {
+                       NEXTFILE(p);
+                       if (!p)
+                               break;
+                       canon(p, name, sizeof(name));
+                       ino = dirlookup(name);
+                       if (ino == 0)
+                               continue;
+                       if (mflag)
+                               pathcheck(name);
+                       treescan(name, ino, addfile);
+               }
+               createfiles();
+#ifdef sunos
+               if (fdsmtc != -1) {
+                       close(fdsmtc);
+               }
+#endif /* sunos */
+#ifdef DEBUG_QFA
+               tiend = time(NULL);
+               titaken = tiend - tistart;
+               msg("writing QFA positions took %d:%02d:%02d\n", titaken / 3600, 
+                       (titaken % 3600) / 60, titaken % 60);
+#endif /* DEBUG_QFA */
+               break;
+#endif /* USE_QFA */
+       }
+       exit(0);
+       /* NOTREACHED */
+       return 0;       /* gcc shut up */
+}
+
+static void
+usage(void)
+{
+       char white[MAXPATHLEN];
+       const char *ext2ver, *ext2date;
+
+       memset(white, ' ', MAXPATHLEN);
+       white[MIN(strlen(__progname), MAXPATHLEN - 1)] = '\0';
+
+#ifdef __linux__
+       ext2fs_get_library_version(&ext2ver, &ext2date);
+       (void)fprintf(stderr, "%s %s (using libext2fs %s of %s)\n", 
+                     __progname, _DUMP_VERSION, ext2ver, ext2date);
+#else
+       (void)fprintf(stderr, "%s %s\n", __progname, _DUMP_VERSION);
+#endif
+
+#ifdef KERBEROS
+#define kerbflag "k"
+#else
+#define kerbflag
+#endif
+
+#ifdef USE_QFA
+#define qfaflag "[-Q file] "
+#else
+#define qfaflag
+#endif
+
+       fprintf(stderr,
+               "usage:"
+               "\t%s -C [-cd" kerbflag "lMvVy] [-b blocksize] [-D filesystem] [-f file]\n"
+               "\t%s    [-F script] [-L limit] [-s fileno]\n"
+               "\t%s -i [-acdh" kerbflag "lmMouvVy] [-A file] [-b blocksize] [-f file]\n"
+               "\t%s    [-F script] " qfaflag "[-s fileno]\n"
+#ifdef USE_QFA
+               "\t%s -P file [-acdh" kerbflag "lmMuvVy] [-A file] [-b blocksize]\n"
+               "\t%s    [-f file] [-F script] [-s fileno] [-X filelist] [file ...]\n"
+#endif
+               "\t%s -r [-cd" kerbflag "lMuvVy] [-b blocksize] [-f file] [-F script]\n"
+               "\t%s    [-s fileno] [-T directory]\n"
+               "\t%s -R [-cd" kerbflag "lMuvVy] [-b blocksize] [-f file] [-F script]\n"
+               "\t%s    [-s fileno] [-T directory]\n"
+               "\t%s -t [-cdh" kerbflag "lMuvVy] [-A file] [-b blocksize] [-f file]\n"
+               "\t%s    [-F script] " qfaflag "[-s fileno] [-X filelist] [file ...]\n"
+               "\t%s -x [-acdh" kerbflag "lmMouvVy] [-A file] [-b blocksize] [-f file]\n"
+               "\t%s    [-F script] " qfaflag "[-s fileno] [-X filelist] [file ...]\n",
+               __progname, white, 
+               __progname, white, 
+#ifdef USE_QFA
+               __progname, white, 
+#endif
+               __progname, white,
+               __progname, white, 
+               __progname, white, 
+               __progname, white);
+       exit(1);
+}
+
+/*
+ * obsolete --
+ *     Change set of key letters and ordered arguments into something
+ *     getopt(3) will like.
+ */
+static void
+obsolete(int *argcp, char **argvp[])
+{
+       int argc, flags;
+       char *ap, **argv, *flagsp = NULL, **nargv, *p = NULL;
+
+       /* Setup. */
+       argv = *argvp;
+       argc = *argcp;
+
+       /* Return if no arguments or first argument has leading dash. */
+       ap = argv[1];
+       if (argc == 1 || *ap == '-')
+               return;
+
+       /* Allocate space for new arguments. */
+       if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
+           (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
+               err(1, "malloc args");
+
+       *nargv++ = *argv;
+       argv += 2, argc -= 2;
+
+       for (flags = 0; *ap; ++ap) {
+               switch (*ap) {
+               case 'A':
+               case 'b':
+               case 'D':
+               case 'f':
+               case 'F':
+               case 'L':
+               case 'Q':
+               case 's':
+               case 'T':
+               case 'X':
+                       if (*argv == NULL) {
+                               warnx("option requires an argument -- %c", *ap);
+                               usage();
+                       }
+                       if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
+                               err(1, "malloc arg");
+                       nargv[0][0] = '-';
+                       nargv[0][1] = *ap;
+                       (void)strcpy(&nargv[0][2], *argv);
+                       ++argv;
+                       ++nargv;
+                       break;
+               default:
+                       if (!flags) {
+                               *p++ = '-';
+                               flags = 1;
+                       }
+                       *p++ = *ap;
+                       break;
+               }
+       }
+
+       /* Terminate flags. */
+       if (flags) {
+               *p = '\0';
+               *nargv++ = flagsp;
+       }
+
+       /* Copy remaining arguments. */
+       while ((*nargv++ = *argv++));
+
+       /* Update argument count. */
+       *argcp = nargv - *argvp - 1;
+}
+
+/*
+ * use_stdin --
+ *     reserve stdin for opt (avoid conflicts)
+ */
+void
+use_stdin(const char *opt)
+{
+       if (stdin_opt)
+               errx(1, "can't handle standard input for both %s and %s",
+                       stdin_opt, opt);
+       stdin_opt = opt;
+}
diff --git a/restore/restore.8.in b/restore/restore.8.in
new file mode 100644 (file)
index 0000000..d7f934b
--- /dev/null
@@ -0,0 +1,757 @@
+.\" Copyright (c) 1985, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: restore.8.in,v 1.31 2003/06/11 13:01:36 stelian Exp $
+.\"
+.TH RESTORE 8 "version __VERSION__ of __DATE__" BSD "System management commands"
+.SH NAME
+restore \- restore files or file systems from backups made with dump
+.SH SYNOPSIS
+.B restore \-C 
+[\fB\-cdklMvVy\fR]
+[\fB\-b \fIblocksize\fR]
+[\fB\-D \fIfilesystem\fR]
+[\fB\-f \fIfile\fR]
+[\fB\-F \fIscript\fR]
+[\fB\-L \fIlimit\fR]
+[\fB\-s \fIfileno\fR]
+[\fB\-T \fIdirectory\fR]
+.PP
+.B restore \-i
+[\fB\-acdhklmMNouvVy\fR]
+[\fB\-A \fIfile\fR]
+[\fB\-b \fIblocksize\fR]
+[\fB\-f \fIfile\fR]
+[\fB\-F \fIscript\fR]
+[\fB\-Q \fIfile\fR]
+[\fB\-s \fIfileno\fR]
+[\fB\-T \fIdirectory\fR]
+.PP
+.B restore \-P 
+.I file
+[\fB\-acdhklmMNuvVy\fR]
+[\fB\-A \fIfile\fR]
+[\fB\-b \fIblocksize\fR]
+[\fB\-f \fIfile\fR]
+[\fB\-F \fIscript\fR]
+[\fB\-s \fIfileno\fR]
+[\fB\-T \fIdirectory\fR]
+[\fB\-X \fIfilelist\fR]
+[ \fIfile ... \fR]
+.PP
+.B restore \-R
+[\fB\-cdklMNuvVy\fR]
+[\fB\-b \fIblocksize\fR]
+[\fB\-f \fIfile\fR]
+[\fB\-F \fIscript\fR]
+[\fB\-s \fIfileno\fR]
+[\fB\-T \fIdirectory\fR]
+.PP
+.B restore \-r 
+[\fB\-cdklMNuvVy\fR]
+[\fB\-b \fIblocksize\fR]
+[\fB\-f \fIfile\fR]
+[\fB\-F \fIscript\fR]
+[\fB\-s \fIfileno\fR]
+[\fB\-T \fIdirectory\fR]
+.PP
+.B restore \-t
+[\fB\-cdhklMNuvVy\fR]
+[\fB\-A \fIfile\fR]
+[\fB\-b \fIblocksize\fR]
+[\fB\-f \fIfile\fR]
+[\fB\-F \fIscript\fR]
+[\fB\-Q \fIfile\fR]
+[\fB\-s \fIfileno\fR]
+[\fB\-T \fIdirectory\fR]
+[\fB\-X \fIfilelist\fR]
+[ \fIfile ... \fR]
+.PP
+.B restore \-x 
+[\fB\-adchklmMNouvVy\fR]
+[\fB\-A \fIfile\fR]
+[\fB\-b \fIblocksize\fR]
+[\fB\-f \fIfile\fR]
+[\fB\-F \fIscript\fR]
+[\fB\-Q \fIfile\fR]
+[\fB\-s \fIfileno\fR]
+[\fB\-T \fIdirectory\fR]
+[\fB\-X \fIfilelist\fR]
+[ \fIfile ... \fR]
+.PP
+(The 4.3BSD option syntax is implemented for backward compatibility but is not 
+documented here.)
+.SH DESCRIPTION
+The
+.B restore
+command performs the inverse function of
+.BR dump (8).
+A full backup of a file system may be restored and subsequent incremental
+backups layered on top of it. Single files and directory subtrees may be 
+restored from full or partial backups.
+.B Restore
+works across a network; to do this see the
+.B \-f
+flag described below. Other arguments to the command are file or directory
+names specifying the files that are to be restored. Unless the
+.B \-h
+flag is specified (see below), the appearance of a directory name refers to
+the files and (recursively) subdirectories of that directory.
+.PP
+Exactly one of the following flags is required:
+.TP
+.B \-C
+This mode allows comparison of files from a dump.
+.B Restore
+reads the backup and compares its contents with files present on the disk. It
+first changes its working directory to the root of the filesystem that was 
+dumped and compares the tape with the files in its new current directory. See
+also the
+.B \-L
+flag described below.
+.TP
+.B \-i
+This mode allows interactive restoration of files from a dump. After reading in
+the directory information from the dump,
+.B restore
+provides a shell like interface that allows the user to move around the 
+directory tree selecting files to be extracted. The available commands are 
+given below; for those commands that require an argument, the default is the
+current directory.
+.RS
+.TP
+.B add \fR[\fIarg\fR]
+The current directory or specified argument is added to the list of files to be
+extracted.  If a directory is specified, then it and all its descendents are
+added to the extraction list (unless the
+.B \-h
+flag is specified on the command line). Files that are on the extraction list
+are prepended with a \*(lq*\*(rq when they are listed by 
+.BR ls .
+.TP
+.BI cd " arg"
+Change the current working directory to the specified argument.
+.TP
+.B delete \fR[\fIarg\fR]
+The current directory or specified argument is deleted from the list of files 
+to be extracted. If a directory is specified, then it and all its descendents
+are deleted from the extraction list (unless the
+.B \-h
+flag is specified on the command line). The most expedient way to extract most 
+of the files from a directory is to add the directory to the extraction list
+and then delete those files that are not needed.
+.TP
+.B extract
+All files on the extraction list are extracted from the dump.
+.B Restore
+will ask which volume the user wishes to mount. The fastest way to extract a f
+ew files is to start with the last volume and work towards the first volume.
+.TP
+.B help
+List a summary of the available commands.
+.TP
+.B ls \fR[\fIarg\fR]
+List the current or specified directory. Entries that are directories are 
+appended with a \*(lq/\*(rq. Entries that have been marked for extraction are 
+prepended with a \*(lq*\*(rq. If the verbose flag is set, the inode number of 
+each entry is also listed.
+.TP
+.B pwd
+Print the full pathname of the current working directory.
+.TP
+.B quit
+.B Restore
+immediately exits, even if the extraction list is not empty.
+.TP
+.B setmodes
+All directories that have been added to the extraction list have their owner, 
+modes, and times set; nothing is extracted from the dump. This is useful for 
+cleaning up after a 
+.B restore 
+has been prematurely aborted.
+.TP
+.B verbose
+The sense of the 
+.B \-v
+flag is toggled. When set, the verbose flag causes the 
+.B ls
+command to list the inode numbers of all entries. It also causes
+.B restore
+to print out information about each file as it is extracted.
+.RE
+.TP
+.BI \-P " file"
+.B Restore
+creates a new Quick File Access file 
+.I file
+from an existing dump file without restoring its contents.
+.TP
+.B \-R
+.B Restore
+requests a particular tape of a multi-volume set on which to restart a full 
+restore (see the
+.B \-r
+flag below). This is useful if the restore has been interrupted.
+.TP
+.B \-r
+Restore (rebuild) a file system. The target file system should be made pristine
+with
+.BR mke2fs (8),
+mounted, and the user
+.BR cd 'd
+into the pristine file system before starting the restoration of the initial
+level 0 backup. If the level 0 restores successfully, the
+.B \-r
+flag may be used to restore any necessary incremental backups on top of the
+level 0. The
+.B \-r
+flag precludes an interactive file extraction and can be detrimental to one's 
+health (not to mention the disk) if not used carefully. An example:
+.IP
+.RS 14
+.B mke2fs /dev/sda1
+.TP
+.B mount /dev/sda1 /mnt
+.TP
+.B cd /mnt
+.TP
+.B restore rf /dev/st0
+.RE
+.IP
+Note that 
+.B restore
+leaves a file 
+.I restoresymtable
+in the root directory to pass information between incremental restore passes.
+This file should be removed when the last incremental has been restored.
+.IP
+.BR Restore ,
+in conjunction with
+.BR mke2fs (8)
+and
+.BR dump (8),
+may be used to modify file system parameters such as size or block size.
+.TP
+.B \-t
+The names of the specified files are listed if they occur on the backup. If no 
+file argument is given, the root directory is listed, which results in the
+entire content of the backup being listed, unless the
+.B \-h
+flag has been specified.  Note that the
+.B \-t
+flag replaces the function of the old
+.BR dumpdir (8)
+program.  See also the
+.B \-X
+option below.
+.TP
+.B \-x
+The named files are read from the given media. If a named file matches a 
+directory whose contents are on the backup and the
+.B \-h
+flag is not specified, the directory is recursively extracted. The owner, 
+modification time, and mode are restored (if possible). If no file argument is
+given, the root directory is extracted, which results in the entire content of
+the backup being extracted, unless the
+.B \-h
+flag has been specified.  See also the
+.B \-X
+option below.
+.SH OPTIONS
+The following additional options may be specified:
+.TP
+.B \-a
+In 
+.B \-i
+or
+.B \-x
+mode, 
+.B restore 
+does ask the user for the volume number on which the files to be extracted are 
+supposed to be (in order to minimise the time by reading only the interesting 
+volumes). The 
+.B \-a
+option disables this behaviour and reads all the volumes starting with 1. This 
+option is useful when the operator does not know on which volume the files to 
+be extracted are and/or when he prefers the longer unattended mode rather than
+the shorter interactive mode.
+.TP
+.BI \-A " archive_file"
+Read the table of contents from
+.I archive_file
+instead of the media. This option can be used in combination with the 
+.BR \-t ,
+.BR \-i ,
+or 
+.B \-x 
+options, making it possible to check whether files are on the media without 
+having to mount the media.
+.TP
+.BI \-b " blocksize"
+The number of kilobytes per dump record. If the
+.B \-b
+option is not specified,
+.B restore
+tries to determine the media block size dynamically.
+.TP
+.B \-c
+Normally,
+.B restore
+will try to determine dynamically whether the dump was made from an old 
+(pre-4.4) or new format file system. The
+.B \-c
+flag disables this check, and only allows reading a dump in the old format.
+.TP
+.B \-d
+The
+.B \-d
+(debug) flag causes
+.B restore
+to print debug information.
+.TP
+.BI \-D " filesystem"
+The
+.B \-D
+flag allows the user to specify the filesystem name when using
+.B restore
+with the
+.B \-C
+option to check the backup.
+.TP
+.BI \-f " file"
+Read the backup from
+.IR file ;
+.I file
+may be a special device file like
+.I /dev/st0
+(a tape drive),
+.I /dev/sda1
+(a disk drive), an ordinary file, or
+.I \-
+(the standard input). If the name of the file is of the form
+.I host:file 
+or
+.IR user@host:file ,
+.B restore
+reads from the named file on the remote host using
+.BR rmt (8).
+.TP
+.BI \-F " script"
+Run script at the beginning of each tape. The device name and the current 
+volume number are passed on the command line. The script must return 0 if 
+.B restore
+should continue without asking the user to change the tape, 1 if 
+.B restore
+should continue but ask the user to change the tape. Any other exit code will 
+cause
+.B restore
+to abort. For security reasons,
+.B restore
+reverts back to the real user ID and the real group ID before running the 
+script.
+.TP
+.B \-h
+Extract the actual directory, rather than the files that it references. This 
+prevents hierarchical restoration of complete subtrees from the dump.
+.TP
+.B \-k
+Use Kerberos authentication when contacting the remote tape server. (Only 
+available if this options was enabled when
+.B restore
+was compiled.)
+.TP
+.B \-l
+When doing remote restores, assume the remote file is a regular file (instead
+of a tape device). If you're restoring a remote compressed file, you will need
+to specify this option or 
+.B restore
+will fail to access it correctly.
+.TP
+.BI \-L " limit"
+The
+.B \-L
+flag allows the user to specify a maximal number of miscompares when using
+.B restore
+with the
+.B \-C
+option to check the backup. If this limit is reached, 
+.B restore
+will abort with an error message. A value of 0 (the default value) disables 
+the check.
+.TP
+.B \-m
+Extract by inode numbers rather than by file name. This is useful if only a few
+files are being extracted, and one wants to avoid regenerating the complete 
+pathname to the file.
+.TP
+.B \-M
+Enables the multi-volume feature (for reading dumps made using the 
+.B \-M
+option of dump). The name specified with
+.B \-f
+is treated as a prefix and
+.B restore
+tries to read in sequence from 
+.I <prefix>001, <prefix>002 
+etc. 
+.TP
+.B \-N
+The
+.B \-N
+flag causes
+.B restore
+to perform a full execution as requested by one of
+.BR \-i ,
+.BR \-R ,
+.BR \-r ,
+.B t
+or
+.B x
+command without actually writing any file on disk.
+.TP
+.B \-o
+The
+.B \-o
+flag causes
+.B restore
+to automatically restore the current directory permissions without asking the 
+operator whether to do so in one of
+.B \-i
+or
+.B \-x
+modes.
+.TP
+.BI \-Q " file"
+Use the file
+.I file
+in order to read tape position as stored using the dump Quick File Access mode,
+in one of 
+.BR \-i ,
+.B \-x
+or
+.B \-t
+mode.
+.IP
+It is recommended to set up the st driver to return logical tape positions 
+rather than physical before calling 
+.B dump/restore
+with parameter 
+.BR \-Q .
+Since not all tape devices support physical tape positions those tape devices 
+return an error during
+.B dump/restore
+when the st driver is set to the default physical setting. Please see the
+.BR st (4)
+man page, option 
+.B MTSETDRVBUFFER
+, or the
+.BR mt(1)
+man page, on how to set the driver to return logical tape positions.
+.IP
+Before calling 
+.B restore
+with parameter 
+.BR \-Q ,
+always make sure the st driver is set to return the same type of tape position
+used during the call to
+.BR dump .
+Otherwise
+.B restore
+may be confused.
+.IP
+This option can be used when restoring from local or remote tapes (see above) 
+or from local or remote files.
+.TP
+.BI \-s " fileno"
+Read from the specified
+.I fileno
+on a multi-file tape. File numbering starts at 1.
+.TP
+.BI \-T " directory"
+The
+.B \-T
+flag allows the user to specify a directory to use for the storage of temporary
+files. The default value is 
+.IR /tmp .
+This flag is most useful when restoring files after having booted from a 
+floppy. There might be little or no space on the floppy filesystem, but another
+source of space might exist.
+.TP
+.B \-u
+When creating certain types of files, 
+.B restore
+may generate a warning diagnostic if they already exist in the target 
+directory. To prevent this, the
+.B \-u
+(unlink) flag causes
+.B restore
+to remove old entries before attempting to create new ones.
+.TP
+.B \-v
+Normally
+.B restore
+does its work silently. The
+.B \-v
+(verbose) flag causes it to type the name of each file it treats preceded by 
+its file type.
+.TP
+.B \-V
+Enables reading multi-volume non-tape mediums like CDROMs.
+.TP
+.BI \-X " filelist"
+Read list of files to be listed or extracted from the text file
+.I filelist
+in addition to those specified on the command line. This can be used in 
+conjunction with the
+.B \-t
+or
+.B \-x
+commands. The file
+.I filelist
+should contain file names separated by newlines.
+.I filelist
+may be an ordinary file or
+.I -
+(the standard input).
+.TP
+.B \-y
+Do not ask the user whether to abort the restore in the event of an error.
+Always try to skip over the bad block(s) and continue.
+.SH DIAGNOSTICS
+Complains if it gets a read error. If 
+.B y
+has been specified, or the user responds
+.BR y ,
+.B restore
+will attempt to continue the restore.
+.PP
+If a backup was made using more than one tape volume,
+.B restore
+will notify the user when it is time to mount the next volume. If the
+.B \-x
+or
+.B \-i
+flag has been specified,
+.B restore
+will also ask which volume the user wishes to mount. The fastest way to extract
+a few files is to start with the last volume, and work towards the first volume.
+.PP
+There are numerous consistency checks that can be listed by
+.BR restore .
+Most checks are self-explanatory or can \*(lqnever happen\*(rq. Common errors
+are given below:
+.TP
+.I Converting to new file system format
+A dump tape created from the old file system has been loaded. It is
+automatically converted to the new file system format.
+.TP
+.I <filename>: not found on tape
+The specified file name was listed in the tape directory, but was not found on
+the tape. This is caused by tape read errors while looking for the file, and
+from using a dump tape created on an active file system.
+.TP
+.I expected next file <inumber>, got <inumber>
+A file that was not listed in the directory showed up. This can occur when
+using a dump created on an active file system.
+.TP
+.I Incremental dump too low
+When doing an incremental restore, a dump that was written before the previous 
+incremental dump, or that has too low an incremental level has been loaded.
+.TP
+.I Incremental dump too high
+When doing an incremental restore, a dump that does not begin its coverage
+where the previous incremental dump left off, or that has too high an 
+incremental level has been loaded.
+.TP
+.I Tape read error while restoring <filename>
+.TP
+.I Tape read error while skipping over inode <inumber>
+.TP
+.I Tape read error while trying to resynchronize
+A tape (or other media) read error has occurred. If a file name is specified,
+its contents are probably partially wrong. If an inode is being skipped or the
+tape is trying to resynchronize, no extracted files have been corrupted, though
+files may not be found on the tape.
+.TP
+.I resync restore, skipped <num> blocks
+After a dump read error, 
+.B restore
+may have to resynchronize itself. This message lists the number of blocks that
+were skipped over.
+.SH EXIT STATUS
+.B Restore
+exits with zero status on success. Tape errors are indicated with an exit code
+of 1.
+.PP
+When doing a comparison of files from a dump, an exit code of 2 indicates that
+some files were modified or deleted since the dump was made.
+.SH ENVIRONMENT
+If the following environment variable exists it will be utilized by
+.BR restore :
+.TP
+.B TAPE
+If no
+.B \-f
+option was specified,
+.B restore
+will use the device specified via
+.B TAPE
+as the dump device.
+.B TAPE
+may be of the form
+.IR tapename ,
+.I host:tapename
+or
+.IR user@host:tapename .
+.TP
+.B TMPDIR
+The directory given in
+.B TMPDIR
+will be used instead of
+.I /tmp
+to store temporary files.
+.TP
+.B RMT
+The environment variable
+.B RMT
+will be used to determine the pathname of the remote
+.BR rmt (8)
+program.
+.TP
+.B RSH
+.B Restore
+uses the contents of this variable to determine the name of the remote shell 
+command to use when doing a network restore (rsh, ssh etc.). If this variable
+is not set,
+.BR rcmd (3)
+will be used, but only root will be able to do a network restore.
+.SH FILES
+.TP
+.I /dev/st0
+the default tape drive
+.TP
+.I /tmp/rstdir*
+file containing directories on the tape
+.TP
+.I /tmp/rstmode*
+owner, mode, and time stamps for directories
+.TP
+.I ./restoresymtable
+information passed between incremental restores
+.SH SEE ALSO
+.BR dump (8),
+.BR mount (8),
+.BR mke2fs (8),
+.BR rmt (8)
+.SH BUGS
+.B Restore
+can get confused when doing incremental restores from dumps that were made on
+active file systems.
+.PP
+A level 0 dump must be done after a full restore. Because 
+.B restore
+runs in user code, it has no control over inode allocation; thus a full dump
+must be done to get a new set of directories reflecting the new inode 
+numbering, even though the content of the files is unchanged.
+.PP
+The temporary files
+.I /tmp/rstdir*
+and
+.I /tmp/rstmode*
+are generated with a unique name based on the date of the dump and the process
+ID (see
+.BR mktemp (3) ),
+except when
+.B \-r
+or
+.B \-R
+is used. Because
+.B \-R
+allows you to restart a
+.B \-r
+operation that may have been interrupted, the temporary files should be the 
+same across different processes. In all other cases, the files are unique 
+because it is possible to have two different dumps started at the same time, 
+and separate operations shouldn't conflict with each other.
+.PP
+To do a network restore, you have to run 
+.B restore
+as root or use a remote shell replacement (see 
+.B RSH
+variable).  This is due to the previous security history of 
+.B dump 
+and
+.BR restore .
+(
+.B restore
+is written to be setuid root, but we are not certain all bugs are gone from the
+code - run setuid at your own risk.)
+.PP
+At the end of restores in
+.B \-i
+or
+.B \-x
+modes (unless
+.B \-o
+option is in use),
+.B restore
+will ask the operator whether to set the permissions on the current
+directory. If the operator confirms this action, the permissions 
+on the directory from where 
+.B restore
+was launched will be replaced by the permissions on the dumped root
+inode. Although this behaviour is not really a bug, it has proven itself
+to be confusing for many users, so it is recommended to answer 'no', 
+unless you're performing a full restore and you do want to restore the
+permissions on '/'.
+.PP
+It should be underlined that because it runs in user code,
+.B restore
+, when run with the
+.B \-C
+option, sees the files as the kernel presents them, whereas
+.B dump
+sees all the files on a given filesystem. In particular, this 
+can cause some confusion when comparing a dumped filesystem a part
+of which is hidden by a filesystem mounted on top of it.
+.SH AUTHOR
+The
+.B dump/restore
+backup suite was ported to Linux's Second Extended File System by Remy Card 
+<card@Linux.EU.Org>. He maintained the initial versions of 
+.B dump
+(up and including 0.4b4, released in january 1997).
+.PP
+Starting with 0.4b5, the new maintainer is Stelian Pop <stelian@popies.net>.
+.SH AVAILABILITY
+The
+.B dump/restore
+backup suite is available from <http://dump.sourceforge.net>
+.SH HISTORY
+The
+.B restore
+command appeared in 4.2BSD.
diff --git a/restore/restore.c b/restore/restore.c
new file mode 100644 (file)
index 0000000..b95e356
--- /dev/null
@@ -0,0 +1,1209 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: restore.c,v 1.33 2003/11/22 16:52:16 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <sys/types.h>
+
+#ifdef __linux__
+#include <sys/param.h>
+#include <sys/time.h>
+#include <time.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <bsdcompat.h>
+#else  /* __linux__ */
+#ifdef sunos
+#include <sys/fcntl.h>
+#include <bsdcompat.h>
+#else
+#include <ufs/ufs/dinode.h>
+#endif
+#endif /* __linux__ */
+
+#include <protocols/dumprestore.h>
+
+#include <compaterr.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "restore.h"
+#include "extern.h"
+
+static char *keyval __P((int));
+
+/*
+ * This implements the 't' option.
+ * List entries on the tape.
+ */
+long
+listfile(char *name, dump_ino_t ino, int type)
+{
+       long descend = hflag ? GOOD : FAIL;
+#ifdef USE_QFA
+       long tnum;
+       long long tpos;
+#endif
+
+       if (TSTINO(ino, dumpmap) == 0)
+               return (descend);
+       Vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
+#ifdef USE_QFA
+       if (tapeposflag) {      /* add QFA positions to output */
+               (void)Inode2Tapepos(ino, &tnum, &tpos, 1);
+               fprintf(stdout, "%10lu\t%ld\t%lld\t%s\n", (unsigned long)ino, 
+                       tnum, tpos, name);
+       }
+       else
+#endif
+               fprintf(stdout, "%10lu\t%s\n", (unsigned long)ino, name);
+       return (descend);
+}
+
+/*
+ * This implements the 'x' option.
+ * Request that new entries be extracted.
+ */
+long
+addfile(char *name, dump_ino_t ino, int type)
+{
+       struct entry *ep, *np;
+       long descend = hflag ? GOOD : FAIL;
+       char buf[100];
+
+       if (TSTINO(ino, dumpmap) == 0) {
+               Dprintf(stdout, "%s: not on the tape\n", name);
+               return (descend);
+       }
+       if (ino == WINO && command == 'i' && !vflag)
+               return (descend);
+       if (!mflag) {
+               (void) snprintf(buf, sizeof(buf), "./%lu", (unsigned long)ino);
+               name = buf;
+               if (type == NODE) {
+                       (void) genliteraldir(name, ino);
+                       return (descend);
+               }
+       }
+       ep = lookupino(ino);
+       if (ep != NULL) {
+               if (strcmp(name, myname(ep)) == 0) {
+                       ep->e_flags |= NEW;
+                       return (descend);
+               }
+               type |= LINK;
+               for (np = ep->e_links; np; np = np->e_links)
+                       if (strcmp(name, myname(np)) == 0) {
+                               np->e_flags |= NEW;
+                               return (descend);
+                       }
+       }
+       ep = addentry(name, ino, type);
+#ifdef USE_QFA
+       if ((type == NODE) && (!createtapeposflag))
+#else
+       if (type == NODE)
+#endif
+               newnode(ep);
+       ep->e_flags |= NEW;
+       return (descend);
+}
+
+/*
+ * This is used by the 'i' option to undo previous requests made by addfile.
+ * Delete entries from the request queue.
+ */
+/* ARGSUSED */
+long
+deletefile(char *name, dump_ino_t ino, UNUSED(int type))
+{
+       long descend = hflag ? GOOD : FAIL;
+       struct entry *ep;
+
+       if (TSTINO(ino, dumpmap) == 0)
+               return (descend);
+       ep = lookupname(name);
+       if (ep != NULL) {
+               ep->e_flags &= ~NEW;
+               ep->e_flags |= REMOVED;
+               if (ep->e_type != NODE)
+                       freeentry(ep);
+       }
+       return (descend);
+}
+
+/*
+ * The following four routines implement the incremental
+ * restore algorithm. The first removes old entries, the second
+ * does renames and calculates the extraction list, the third
+ * cleans up link names missed by the first two, and the final
+ * one deletes old directories.
+ *
+ * Directories cannot be immediately deleted, as they may have
+ * other files in them which need to be moved out first. As
+ * directories to be deleted are found, they are put on the
+ * following deletion list. After all deletions and renames
+ * are done, this list is actually deleted.
+ */
+static struct entry *removelist;
+
+/*
+ *     Remove invalid whiteouts from the old tree.
+ *     Remove unneeded leaves from the old tree.
+ *     Remove directories from the lookup chains.
+ */
+void
+removeoldleaves(void)
+{
+       struct entry *ep, *nextep;
+       dump_ino_t i, mydirino;
+
+       Vprintf(stdout, "Mark entries to be removed.\n");
+       if ((ep = lookupino(WINO))) {
+               Vprintf(stdout, "Delete whiteouts\n");
+               for ( ; ep != NULL; ep = nextep) {
+                       nextep = ep->e_links;
+                       mydirino = ep->e_parent->e_ino;
+                       /*
+                        * We remove all whiteouts that are in directories
+                        * that have been removed or that have been dumped.
+                        */
+                       if (TSTINO(mydirino, usedinomap) &&
+                           !TSTINO(mydirino, dumpmap))
+                               continue;
+#ifdef __linux__
+                       (void)fprintf(stderr, "BUG! Should call delwhiteout\n");
+#else
+#ifdef sunos
+#else
+                       delwhiteout(ep);
+#endif
+#endif
+                       freeentry(ep);
+               }
+       }
+       for (i = ROOTINO + 1; i < maxino; i++) {
+               ep = lookupino(i);
+               if (ep == NULL)
+                       continue;
+               if (TSTINO(i, usedinomap))
+                       continue;
+               for ( ; ep != NULL; ep = ep->e_links) {
+                       Dprintf(stdout, "%s: REMOVE\n", myname(ep));
+                       if (ep->e_type == LEAF) {
+                               removeleaf(ep);
+                               freeentry(ep);
+                       } else {
+                               mktempname(ep);
+                               deleteino(ep->e_ino);
+                               ep->e_next = removelist;
+                               removelist = ep;
+                       }
+               }
+       }
+}
+
+/*
+ *     For each directory entry on the incremental tape, determine which
+ *     category it falls into as follows:
+ *     KEEP - entries that are to be left alone.
+ *     NEW - new entries to be added.
+ *     EXTRACT - files that must be updated with new contents.
+ *     LINK - new links to be added.
+ *     Renames are done at the same time.
+ */
+long
+nodeupdates(char *name, dump_ino_t ino, int type)
+{
+       struct entry *ep, *np, *ip;
+       long descend = GOOD;
+       int lookuptype = 0;
+       int key = 0;
+               /* key values */
+#              define ONTAPE   0x1     /* inode is on the tape */
+#              define INOFND   0x2     /* inode already exists */
+#              define NAMEFND  0x4     /* name already exists */
+#              define MODECHG  0x8     /* mode of inode changed */
+
+       /*
+        * This routine is called once for each element in the
+        * directory hierarchy, with a full path name.
+        * The "type" value is incorrectly specified as LEAF for
+        * directories that are not on the dump tape.
+        *
+        * Check to see if the file is on the tape.
+        */
+       if (TSTINO(ino, dumpmap))
+               key |= ONTAPE;
+       /*
+        * Check to see if the name exists, and if the name is a link.
+        */
+       np = lookupname(name);
+       if (np != NULL) {
+               key |= NAMEFND;
+               ip = lookupino(np->e_ino);
+               if (ip == NULL)
+                       panic("corrupted symbol table\n");
+               if (ip != np)
+                       lookuptype = LINK;
+       }
+       /*
+        * Check to see if the inode exists, and if one of its links
+        * corresponds to the name (if one was found).
+        */
+       ip = lookupino(ino);
+       if (ip != NULL) {
+               key |= INOFND;
+               for (ep = ip->e_links; ep != NULL; ep = ep->e_links) {
+                       if (ep == np) {
+                               ip = ep;
+                               break;
+                       }
+               }
+       }
+       /*
+        * If both a name and an inode are found, but they do not
+        * correspond to the same file, then both the inode that has
+        * been found and the inode corresponding to the name that
+        * has been found need to be renamed. The current pathname
+        * is the new name for the inode that has been found. Since
+        * all files to be deleted have already been removed, the
+        * named file is either a now unneeded link, or it must live
+        * under a new name in this dump level. If it is a link, it
+        * can be removed. If it is not a link, it is given a
+        * temporary name in anticipation that it will be renamed
+        * when it is later found by inode number.
+        */
+       if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
+               if (lookuptype == LINK) {
+                       removeleaf(np);
+                       freeentry(np);
+               } else {
+                       Dprintf(stdout, "name/inode conflict, mktempname %s\n",
+                               myname(np));
+                       mktempname(np);
+               }
+               np = NULL;
+               key &= ~NAMEFND;
+       }
+       if ((key & ONTAPE) &&
+         (((key & INOFND) && ip->e_type != type) ||
+          ((key & NAMEFND) && np->e_type != type)))
+               key |= MODECHG;
+
+       /*
+        * Decide on the disposition of the file based on its flags.
+        * Note that we have already handled the case in which
+        * a name and inode are found that correspond to different files.
+        * Thus if both NAMEFND and INOFND are set then ip == np.
+        */
+       switch (key) {
+
+       /*
+        * A previously existing file has been found.
+        * Mark it as KEEP so that other links to the inode can be
+        * detected, and so that it will not be reclaimed by the search
+        * for unreferenced names.
+        */
+       case INOFND|NAMEFND:
+               ip->e_flags |= KEEP;
+               Dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
+                       flagvalues(ip));
+               break;
+
+       /*
+        * A file on the tape has a name which is the same as a name
+        * corresponding to a different file in the previous dump.
+        * Since all files to be deleted have already been removed,
+        * this file is either a now unneeded link, or it must live
+        * under a new name in this dump level. If it is a link, it
+        * can simply be removed. If it is not a link, it is given a
+        * temporary name in anticipation that it will be renamed
+        * when it is later found by inode number (see INOFND case
+        * below). The entry is then treated as a new file.
+        */
+       case ONTAPE|NAMEFND:
+       case ONTAPE|NAMEFND|MODECHG:
+               if (lookuptype == LINK) {
+                       removeleaf(np);
+                       freeentry(np);
+               } else {
+                       mktempname(np);
+               }
+               /* fall through */
+
+       /*
+        * A previously non-existent file.
+        * Add it to the file system, and request its extraction.
+        * If it is a directory, create it immediately.
+        * (Since the name is unused there can be no conflict)
+        */
+       case ONTAPE:
+               ep = addentry(name, ino, type);
+               if (type == NODE)
+                       newnode(ep);
+               ep->e_flags |= NEW|KEEP;
+               Dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
+                       flagvalues(ep));
+               break;
+
+       /*
+        * A file with the same inode number, but a different
+        * name has been found. If the other name has not already
+        * been found (indicated by the KEEP flag, see above) then
+        * this must be a new name for the file, and it is renamed.
+        * If the other name has been found then this must be a
+        * link to the file. Hard links to directories are not
+        * permitted, and are either deleted or converted to
+        * symbolic links. Finally, if the file is on the tape,
+        * a request is made to extract it.
+        */
+       case ONTAPE|INOFND:
+               if (type == LEAF && (ip->e_flags & KEEP) == 0)
+                       ip->e_flags |= EXTRACT;
+               /* fall through */
+       case INOFND:
+               if ((ip->e_flags & KEEP) == 0) {
+                       renameit(myname(ip), name);
+                       moveentry(ip, name);
+                       ip->e_flags |= KEEP;
+                       Dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
+                               flagvalues(ip));
+                       break;
+               }
+               if (ip->e_type == NODE) {
+                       descend = FAIL;
+                       fprintf(stderr,
+                               "deleted hard link %s to directory %s\n",
+                               name, myname(ip));
+                       break;
+               }
+               ep = addentry(name, ino, type|LINK);
+               ep->e_flags |= NEW;
+               Dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
+                       flagvalues(ep));
+               break;
+
+       /*
+        * A previously known file which is to be updated. If it is a link,
+        * then all names referring to the previous file must be removed
+        * so that the subset of them that remain can be recreated.
+        */
+       case ONTAPE|INOFND|NAMEFND:
+               if (lookuptype == LINK) {
+                       removeleaf(np);
+                       freeentry(np);
+                       ep = addentry(name, ino, type|LINK);
+                       if (type == NODE)
+                               newnode(ep);
+                       ep->e_flags |= NEW|KEEP;
+                       Dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
+                               flagvalues(ep));
+                       break;
+               }
+               if (type == LEAF && lookuptype != LINK)
+                       np->e_flags |= EXTRACT;
+               np->e_flags |= KEEP;
+               Dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
+                       flagvalues(np));
+               break;
+
+       /*
+        * An inode is being reused in a completely different way.
+        * Normally an extract can simply do an "unlink" followed
+        * by a "creat". Here we must do effectively the same
+        * thing. The complications arise because we cannot really
+        * delete a directory since it may still contain files
+        * that we need to rename, so we delete it from the symbol
+        * table, and put it on the list to be deleted eventually.
+        * Conversely if a directory is to be created, it must be
+        * done immediately, rather than waiting until the
+        * extraction phase.
+        */
+       case ONTAPE|INOFND|MODECHG:
+       case ONTAPE|INOFND|NAMEFND|MODECHG:
+               if (ip->e_flags & KEEP) {
+                       badentry(ip, "cannot KEEP and change modes");
+                       break;
+               }
+               if (ip->e_type == LEAF) {
+                       /* changing from leaf to node */
+                       for ( ; ip != NULL; ip = ip->e_links) {
+                               if (ip->e_type != LEAF)
+                                       badentry(ip, "NODE and LEAF links to same inode");
+                               removeleaf(ip);
+                               freeentry(ip);
+                       }
+                       ip = addentry(name, ino, type);
+                       newnode(ip);
+               } else {
+                       /* changing from node to leaf */
+                       if ((ip->e_flags & TMPNAME) == 0)
+                               mktempname(ip);
+                       deleteino(ip->e_ino);
+                       ip->e_next = removelist;
+                       removelist = ip;
+                       ip = addentry(name, ino, type);
+               }
+               ip->e_flags |= NEW|KEEP;
+               Dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
+                       flagvalues(ip));
+               break;
+
+       /*
+        * A hard link to a directory that has been removed.
+        * Ignore it.
+        */
+       case NAMEFND:
+               Dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key),
+                       name);
+               descend = FAIL;
+               break;
+
+       /*
+        * If we find a directory entry for a file that is not on
+        * the tape, then we must have found a file that was created
+        * while the dump was in progress. Since we have no contents
+        * for it, we discard the name knowing that it will be on the
+        * next incremental tape.
+        */
+       case 0:
+               if (compare_ignore_not_found) break;
+               fprintf(stderr, "%s: (inode %lu) not found on tape\n",
+                       name, (unsigned long)ino);
+               do_compare_error;
+               break;
+
+       /*
+        * If any of these arise, something is grievously wrong with
+        * the current state of the symbol table.
+        */
+       case INOFND|NAMEFND|MODECHG:
+       case NAMEFND|MODECHG:
+       case INOFND|MODECHG:
+               fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key),
+                       name);
+               break;
+
+       /*
+        * These states "cannot" arise for any state of the symbol table.
+        */
+       case ONTAPE|MODECHG:
+       case MODECHG:
+       default:
+               panic("[%s] %s: impossible state\n", keyval(key), name);
+               break;
+       }
+       return (descend);
+}
+
+/*
+ * Calculate the active flags in a key.
+ */
+static char *
+keyval(int key)
+{
+       static char keybuf[32];
+
+       (void) strcpy(keybuf, "|NIL");
+       keybuf[0] = '\0';
+       if (key & ONTAPE)
+               (void) strcat(keybuf, "|ONTAPE");
+       if (key & INOFND)
+               (void) strcat(keybuf, "|INOFND");
+       if (key & NAMEFND)
+               (void) strcat(keybuf, "|NAMEFND");
+       if (key & MODECHG)
+               (void) strcat(keybuf, "|MODECHG");
+       return (&keybuf[1]);
+}
+
+/*
+ * Find unreferenced link names.
+ */
+void
+findunreflinks(void)
+{
+       struct entry *ep, *np;
+       dump_ino_t i;
+
+       Vprintf(stdout, "Find unreferenced names.\n");
+       for (i = ROOTINO; i < maxino; i++) {
+               ep = lookupino(i);
+               if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0)
+                       continue;
+               for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
+                       if (np->e_flags == 0) {
+                               Dprintf(stdout,
+                                   "%s: remove unreferenced name\n",
+                                   myname(np));
+                               removeleaf(np);
+                               freeentry(np);
+                       }
+               }
+       }
+       /*
+        * Any leaves remaining in removed directories is unreferenced.
+        */
+       for (ep = removelist; ep != NULL; ep = ep->e_next) {
+               for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
+                       if (np->e_type == LEAF) {
+                               if (np->e_flags != 0)
+                                       badentry(np, "unreferenced with flags");
+                               Dprintf(stdout,
+                                   "%s: remove unreferenced name\n",
+                                   myname(np));
+                               removeleaf(np);
+                               freeentry(np);
+                       }
+               }
+       }
+}
+
+/*
+ * Remove old nodes (directories).
+ * Note that this routine runs in O(N*D) where:
+ *     N is the number of directory entries to be removed.
+ *     D is the maximum depth of the tree.
+ * If N == D this can be quite slow. If the list were
+ * topologically sorted, the deletion could be done in
+ * time O(N).
+ */
+void
+removeoldnodes(void)
+{
+       struct entry *ep, **prev;
+       long change;
+
+       Vprintf(stdout, "Remove old nodes (directories).\n");
+       do      {
+               change = 0;
+               prev = &removelist;
+               for (ep = removelist; ep != NULL; ep = *prev) {
+                       if (ep->e_entries != NULL) {
+                               prev = &ep->e_next;
+                               continue;
+                       }
+                       *prev = ep->e_next;
+                       removenode(ep);
+                       freeentry(ep);
+                       change++;
+               }
+       } while (change);
+       for (ep = removelist; ep != NULL; ep = ep->e_next)
+               badentry(ep, "cannot remove, non-empty");
+}
+
+/* Compare the file specified in `ep' (which is on tape) to the */
+/* current copy of this file on disk.  If do_compare is 0, then just */
+/* make our caller think we did it--this is used to handle hard links */
+/* to files and devices. */
+static void
+compare_entry(struct entry *ep, int do_compare)
+{
+       if ((ep->e_flags & (NEW|EXTRACT)) == 0) {
+               badentry(ep, "unexpected file on tape");
+               do_compare_error;
+       }
+       if (do_compare) (void) comparefile(myname(ep));
+       ep->e_flags &= ~(NEW|EXTRACT);
+}
+
+/*
+ * This is the routine used to compare files for the 'C' command.
+ */
+void
+compareleaves(void)
+{
+       struct entry *ep;
+       dump_ino_t first;
+       long curvol;
+
+       first = lowerbnd(ROOTINO);
+       curvol = volno;
+       while (curfile.ino < maxino) {
+               first = lowerbnd(first);
+               /*
+                * If the next available file is not the one which we
+                * expect then we have missed one or more files. Since
+                * we do not request files that were not on the tape,
+                * the lost files must have been due to a tape read error,
+                * or a file that was removed while the dump was in progress.
+                */
+               while (first < curfile.ino) {
+                       ep = lookupino(first);
+                       if (ep == NULL)
+                               panic("%d: bad first\n", first);
+                       fprintf(stderr, "%s: not found on tape\n", myname(ep));
+                       do_compare_error;
+                       ep->e_flags &= ~(NEW|EXTRACT);
+                       first = lowerbnd(first);
+               }
+               /*
+                * If we find files on the tape that have no corresponding
+                * directory entries, then we must have found a file that
+                * was created while the dump was in progress. Since we have 
+                * no name for it, we discard it knowing that it will be
+                * on the next incremental tape.
+                */
+               if (first != curfile.ino) {
+                       fprintf(stderr, "expected next file %ld, got %lu\n",
+                               (long)first, (unsigned long)curfile.ino);
+                       do_compare_error;
+                       skipfile();
+                       goto next;
+               }
+               ep = lookupino(curfile.ino);
+               if (ep == NULL) {
+                       panic("unknown file on tape\n");
+                       do_compare_error;
+               }
+               compare_entry(ep, 1);
+               for (ep = ep->e_links; ep != NULL; ep = ep->e_links) {
+                       compare_entry(ep, 0);
+               }
+
+               /*
+                * We checkpoint the restore after every tape reel, so
+                * as to simplify the amount of work re quired by the
+                * 'R' command.
+                */
+       next:
+               if (curvol != volno) {
+                       skipmaps();
+                       curvol = volno;
+               }
+       }
+       /*
+        * If we encounter the end of the tape and the next available
+        * file is not the one which we expect then we have missed one
+        * or more files. Since we do not request files that were not 
+        * on the tape, the lost files must have been due to a tape 
+        * read error, or a file that was removed while the dump was
+        * in progress.
+        */
+       first = lowerbnd(first);
+       while (first < curfile.ino) {
+               ep = lookupino(first);
+               if (ep == NULL)
+                       panic("%d: bad first\n", first);
+               fprintf(stderr, "%s: (inode %lu) not found on tape\n", 
+                       myname(ep), (unsigned long)first);
+               do_compare_error;
+               ep->e_flags &= ~(NEW|EXTRACT);
+               first = lowerbnd(first);
+       }
+}
+
+/*
+ * This is the routine used to extract files for the 'r' command.
+ * Extract new leaves.
+ */
+void
+createleaves(char *symtabfile)
+{
+       struct entry *ep;
+       dump_ino_t first;
+       long curvol;
+       int doremove;
+
+       if (command == 'R') {
+               Vprintf(stdout, "Continue extraction of new leaves\n");
+       } else {
+               Vprintf(stdout, "Extract new leaves.\n");
+               dumpsymtable(symtabfile, volno);
+       }
+       first = lowerbnd(ROOTINO);
+       curvol = volno;
+       while (curfile.ino < maxino) {
+               first = lowerbnd(first);
+               /*
+                * If the next available file is not the one which we
+                * expect then we have missed one or more files. Since
+                * we do not request files that were not on the tape,
+                * the lost files must have been due to a tape read error,
+                * or a file that was removed while the dump was in progress.
+                */
+               while (first < curfile.ino) {
+                       ep = lookupino(first);
+                       if (ep == NULL)
+                               panic("%d: bad first\n", first);
+                       fprintf(stderr, "%s: (inode %lu) not found on tape\n", 
+                               myname(ep), (unsigned long)first);
+                       ep->e_flags &= ~(NEW|EXTRACT);
+                       first = lowerbnd(first);
+               }
+               /*
+                * If we find files on the tape that have no corresponding
+                * directory entries, then we must have found a file that
+                * was created while the dump was in progress. Since we have
+                * no name for it, we discard it knowing that it will be
+                * on the next incremental tape.
+                */
+               if (first != curfile.ino) {
+                       fprintf(stderr, "expected next file %ld, got %lu\n",
+                               (long)first, (unsigned long)curfile.ino);
+                       skipfile();
+                       goto next;
+               }
+               ep = lookupino(curfile.ino);
+               if (ep == NULL)
+                       panic("unknown file on tape\n");
+               if ((ep->e_flags & (NEW|EXTRACT)) == 0)
+                       badentry(ep, "unexpected file on tape");
+               /*
+                * If the file is to be extracted, then the old file must
+                * be removed since its type may change from one leaf type
+                * to another (e.g. "file" to "character special").
+                */
+               if ((ep->e_flags & EXTRACT) != 0)
+                       doremove = 1;
+               else
+                       doremove = 0;
+               (void) extractfile(ep, doremove);
+               ep->e_flags &= ~(NEW|EXTRACT);
+
+finderres:
+               if ((first == curfile.ino) && (spcl.c_flags & DR_EXTATTRIBUTES)) {
+                       switch (spcl.c_extattributes) {
+                       case EXT_MACOSFNDRINFO:
+#ifdef DUMP_MACOSX
+                               (void)extractfinderinfoufs(myname(ep));
+#else
+                               msg("MacOSX not supported in this version, skipping\n");
+                               skipfile();
+#endif
+                               break;
+                       case EXT_MACOSRESFORK:
+#ifdef DUMP_MACOSX
+                               (void)extractresourceufs(myname(ep));
+#else
+                               msg("MacOSX not supported in this version, skipping\n");
+                               skipfile();
+#endif
+                               break;
+                       case EXT_ACL:
+                               msg("ACLs not supported in this version, skipping\n");
+                               skipfile();
+                               break;
+                       default:
+                               msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes);
+                               skipfile();
+                               break;
+                       }
+                       goto finderres;
+               }
+
+               /*
+                * We checkpoint the restore after every tape reel, so
+                * as to simplify the amount of work required by the
+                * 'R' command.
+                */
+next:
+               if (curvol != volno) {
+                       dumpsymtable(symtabfile, volno);
+                       skipmaps();
+                       curvol = volno;
+               }
+       }
+       /*
+        * If we encounter the end of the tape and the next available
+        * file is not the one which we expect then we have missed one
+        * or more files. Since we do not request files that were not 
+        * on the tape, the lost files must have been due to a tape 
+        * read error, or a file that was removed while the dump was
+        * in progress.
+        */
+       first = lowerbnd(first);
+       while (first < curfile.ino) {
+               ep = lookupino(first);
+               if (ep == NULL)
+                       panic("%d: bad first\n", first);
+               fprintf(stderr, "%s: (inode %lu) not found on tape\n", 
+                       myname(ep), (unsigned long)first);
+               do_compare_error;
+               ep->e_flags &= ~(NEW|EXTRACT);
+               first = lowerbnd(first);
+       }
+}
+
+/*
+ * This is the routine used to extract files for the 'x' and 'i' commands.
+ * Efficiently extract a subset of the files on a tape.
+ */
+void
+createfiles(void)
+{
+       dump_ino_t first, next, last;
+       struct entry *ep;
+       long curvol;
+#ifdef USE_QFA
+       long tnum, tmpcnt;
+       long long tpos, curtpos = 0;
+       time_t tistart, tiend, titaken;
+       int             volChg;
+#endif
+
+       Vprintf(stdout, "Extract requested files\n");
+       curfile.action = SKIP;
+#ifdef USE_QFA
+       if (tapeposflag)
+               curfile.ino = 0;
+       else
+#endif
+               if (volinfo[1] == ROOTINO)
+                       curfile.ino = 0;
+               else
+                       getvol((long)1);
+       skipmaps();
+       skipdirs();
+       first = lowerbnd(ROOTINO);
+       last = upperbnd(maxino - 1);
+       for (;;) {
+#ifdef USE_QFA
+               tmpcnt = 1;
+#endif
+               first = lowerbnd(first);
+               last = upperbnd(last);
+               /*
+                * Check to see if any files remain to be extracted
+                */
+               if (first > last)
+                       return;
+               /*
+                * Reject any volumes with inodes greater
+                * than the last one needed
+                */
+               while (curfile.ino > last) {
+                       curfile.action = SKIP;
+                       if (!pipein)
+                               getvol((long)0);
+                       if (curfile.ino == maxino) {
+                               next = lowerbnd(first);
+                               while (next < curfile.ino) {
+                                       ep = lookupino(next);
+                                       if (ep == NULL)
+                                               panic("corrupted symbol table\n");
+                                       fprintf(stderr, "%s: (inode %lu) not found on tape\n", 
+                                               myname(ep), (unsigned long)next);
+                                       ep->e_flags &= ~NEW;
+                                       next = lowerbnd(next);
+                               }
+                               return;
+                       }
+                       skipmaps();
+                       skipdirs();
+               }
+               /*
+                * Decide on the next inode needed.
+                * Skip across the inodes until it is found
+                * or an out of order volume change is encountered
+                */
+               next = lowerbnd(curfile.ino);
+#ifdef USE_QFA
+               tistart = time(NULL);
+               if (tapeposflag) {
+                       /* get tape position for inode */
+                       (void)Inode2Tapepos(next, &tnum, &tpos, 0);
+                       if (tpos != 0) {
+                               if (tnum != volno) {
+                                       (void)RequestVol(tnum);
+                                       volChg = 1;
+                               } else {
+                                       volChg = 0;
+                               }
+                               if (GetTapePos(&curtpos) == 0) {
+                                       /*  curtpos +1000 ???, some drives 
+                                        *  might be too slow */
+                                       if (((tpos > (curtpos + 1000)) && (volChg == 0)) || ((tpos != curtpos) && (volChg == 1))) {
+                                               volChg = 0;
+#ifdef DEBUG_QFA
+                                               msg("positioning tape %ld from %lld to %lld for inode %lu ...\n", volno, curtpos, tpos, (unsigned long)next);
+#endif
+                                               if (GotoTapePos(tpos) == 0) {
+#ifdef DEBUG_QFA
+                                                       if (GetTapePos(&curtpos) == 0) {
+                                                               msg("before resnyc at tape position %lld (%ld, %ld, %s)\n", curtpos, next, curfile.ino, curfile.name);
+                                                       }
+#endif
+                                                       ReReadInodeFromTape(next);
+#ifdef DEBUG_QFA
+                                                       if (GetTapePos(&curtpos) == 0) {
+                                                               msg("after resnyc at tape position %lld (%ld, %ld, %s)\n", curtpos, next, curfile.ino, curfile.name);
+                                                       }
+#endif
+                                               }
+                                       } else {
+#ifdef DEBUG_QFA
+                                               msg("already at tape %ld position %ld for inode %lu ...\n", volno, tpos, (unsigned long)next);
+#endif
+                                       }
+                               }
+                       }
+               }
+               else
+#endif /* USA_QFA */
+                       if (volinfo[1] == ROOTINO) {
+                               int i, goodvol = 1;
+
+                               for (i = 1; i < (int)TP_NINOS && volinfo[i] != 0; ++i)
+                                       if (volinfo[i] < next)
+                                               goodvol = i;
+
+                               if (goodvol != volno)
+                                       RequestVol(goodvol);
+                       }
+
+               do      {
+                       curvol = volno;
+                       while (next > curfile.ino && volno == curvol) {
+#ifdef USE_QFA
+                               ++tmpcnt;
+#endif
+                               skipfile();
+                       }
+                       skipmaps();
+                       skipdirs();
+               } while (volno == curvol + 1);
+#ifdef USE_QFA
+               tiend = time(NULL);
+               titaken = tiend - tistart;
+#ifdef DEBUG_QFA
+               if (titaken / 60 > 0)
+                       msg("%ld reads took %d:%02d:%02d\n", 
+                               tmpcnt, titaken / 3600, 
+                               (titaken % 3600) / 60, titaken % 60);
+#endif
+#endif /* USE_QFA */
+
+               /*
+                * If volume change out of order occurred the
+                * current state must be recalculated
+                */
+               if (volno != curvol)
+                       continue;
+               /*
+                * If the current inode is greater than the one we were
+                * looking for then we missed the one we were looking for.
+                * Since we only attempt to extract files listed in the
+                * dump map, the lost files must have been due to a tape
+                * read error, or a file that was removed while the dump
+                * was in progress. Thus we report all requested files
+                * between the one we were looking for, and the one we
+                * found as missing, and delete their request flags.
+                */
+               while (next < curfile.ino) {
+                       ep = lookupino(next);
+                       if (ep == NULL)
+                               panic("corrupted symbol table\n");
+#ifdef USE_QFA
+                       if (!createtapeposflag)
+#endif
+                               fprintf(stderr, "%s: (inode %lu) not found on tape\n", 
+                                       myname(ep), (unsigned long)next);
+                       ep->e_flags &= ~NEW;
+                       next = lowerbnd(next);
+               }
+               /*
+                * The current inode is the one that we are looking for,
+                * so extract it per its requested name.
+                */
+               if (next == curfile.ino && next <= last) {
+                       ep = lookupino(next);
+                       if (ep == NULL)
+                               panic("corrupted symbol table\n");
+#ifdef USE_QFA
+                       if (createtapeposflag) {
+#ifdef DEBUG_QFA
+                               msg("inode %ld at tapepos %ld\n", curfile.ino, curtapepos);
+#endif
+                               sprintf(gTps, "%ld\t%ld\t%lld\n", (unsigned long)curfile.ino, volno, curtapepos);
+                               if (write(gTapeposfd, gTps, strlen(gTps)) != (ssize_t)strlen(gTps))
+                                       warn("error writing tapepos file.\n");
+                               skipfile();
+                       } else {
+#endif /* USE_QFA */
+                               (void) extractfile(ep, 0);
+
+finderres:
+                               if ((next == curfile.ino) && (spcl.c_flags & DR_EXTATTRIBUTES)) {
+                                       switch (spcl.c_extattributes) {
+                                       case EXT_MACOSFNDRINFO:
+#ifdef DUMP_MACOSX
+                                               (void)extractfinderinfoufs(myname(ep));
+#else
+                                               msg("MacOSX not supported in this version, skipping\n");
+                                               skipfile();
+#endif
+                                               break;
+                                       case EXT_MACOSRESFORK:
+#ifdef DUMP_MACOSX
+                                               (void)extractresourceufs(myname(ep));
+#else
+                                               msg("MacOSX not supported in this version, skipping\n");
+                                               skipfile();
+#endif
+                                               break;
+                                       case EXT_ACL:
+                                               msg("ACLs not supported in this version, skipping\n");
+                                               skipfile();
+                                               break;
+                                       default:
+                                               msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes);
+                                               skipfile();
+                                               break;
+                                       }
+                                       goto finderres;
+                               }
+
+#ifdef USE_QFA
+                       }
+#endif /* USE_QFA */
+                       ep->e_flags &= ~NEW;
+                       if (volno != curvol)
+                               skipmaps();
+               }
+       }
+}
+
+/*
+ * Add links.
+ */
+void
+createlinks(void)
+{
+       struct entry *np, *ep;
+       dump_ino_t i;
+       char name[BUFSIZ];
+
+       if ((ep = lookupino(WINO))) {
+               Vprintf(stdout, "Add whiteouts\n");
+               for ( ; ep != NULL; ep = ep->e_links) {
+                       if ((ep->e_flags & NEW) == 0)
+                               continue;
+#ifdef __linux__
+                       (void)fprintf(stderr, "BUG! Should call addwhiteout\n");
+#else
+#ifdef sunos
+#else
+                       (void) addwhiteout(myname(ep));
+#endif
+#endif
+                       ep->e_flags &= ~NEW;
+               }
+       }
+       Vprintf(stdout, "Add links\n");
+       for (i = ROOTINO; i < maxino; i++) {
+               ep = lookupino(i);
+               if (ep == NULL)
+                       continue;
+               for (np = ep->e_links; np != NULL; np = np->e_links) {
+                       if ((np->e_flags & NEW) == 0)
+                               continue;
+                       (void) strcpy(name, myname(ep));
+                       if (ep->e_type == NODE) {
+                               (void) linkit(name, myname(np), SYMLINK);
+                       } else {
+                               (void) linkit(name, myname(np), HARDLINK);
+                       }
+                       np->e_flags &= ~NEW;
+               }
+       }
+}
+
+/*
+ * Check the symbol table.
+ * We do this to insure that all the requested work was done, and
+ * that no temporary names remain.
+ */
+void
+checkrestore(void)
+{
+       struct entry *ep;
+       dump_ino_t i;
+
+       Vprintf(stdout, "Check the symbol table.\n");
+       for (i = WINO; i < maxino; i++) {
+               for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
+                       ep->e_flags &= ~KEEP;
+                       if (ep->e_type == NODE)
+                               ep->e_flags &= ~(NEW|EXISTED);
+                       if (ep->e_flags /* != NULL */)
+                               badentry(ep, "incomplete operations");
+               }
+       }
+}
+
+/*
+ * Compare with the directory structure on the tape
+ * A paranoid check that things are as they should be.
+ */
+long
+verifyfile(char *name, dump_ino_t ino, int type)
+{
+       struct entry *np, *ep;
+       long descend = GOOD;
+
+       ep = lookupname(name);
+       if (ep == NULL) {
+               fprintf(stderr, "Warning: missing name %s\n", name);
+               return (FAIL);
+       }
+       np = lookupino(ino);
+       if (np != ep)
+               descend = FAIL;
+       for ( ; np != NULL; np = np->e_links)
+               if (np == ep)
+                       break;
+       if (np == NULL)
+               panic("missing inumber %d\n", ino);
+       if (ep->e_type == LEAF && type != LEAF)
+               badentry(ep, "type should be LEAF");
+       return (descend);
+}
diff --git a/restore/restore.h b/restore/restore.h
new file mode 100644 (file)
index 0000000..bf6284b
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ *
+ *     $Id: restore.h,v 1.29 2004/04/13 13:04:33 stelian Exp $
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <protocols/dumprestore.h>
+/*
+ * Flags
+ */
+extern int     aflag;          /* automatic volume increment */
+extern char    *Afile;         /* archive file */
+extern int     cvtflag;        /* convert from old to new tape format */
+extern int     bflag;          /* set input block size */
+extern int     dflag;          /* print out debugging info */
+extern int     hflag;          /* restore heirarchies */
+extern int     lflag;          /* assume remote filename is a regular file */
+extern int     Lflag;          /* compare errors limit */
+extern int     mflag;          /* restore by name instead of inode number */
+extern int     Mflag;          /* multi-volume restore */
+extern int     oflag;          /* do restore permissions without asking */
+extern int     Vflag;          /* multi-volume on a single device like CDROM */
+extern int     Nflag;          /* do not write the disk */
+extern int     uflag;          /* unlink symlink targets */
+extern int     vflag;          /* print out actions taken */
+extern int     yflag;          /* always try to recover from tape errors */
+extern int     zflag;          /* tape is in compressed format */
+extern int     ufs2flag;       /* tape is a FreeBSD UFS2 dump */
+extern char*   bot_script;     /* beginning of tape script */
+/*
+ * Global variables
+ */
+extern char    *host;          /* name of the remote host */
+extern char    *dumpmap;       /* map of inodes on this dump tape */
+extern char    *usedinomap;    /* map of inodes that are in use on this fs */
+extern dump_ino_t maxino;      /* highest numbered inode in this file system */
+extern long    dumpnum;        /* location of the dump on this tape */
+extern long    volno;          /* current volume being read */
+extern long    ntrec;          /* number of TP_BSIZE records per tape block */
+extern time_t  dumptime;       /* time that this dump begins */
+extern time_t  dumpdate;       /* time that this dump was made */
+extern char    command;        /* opration being performed */
+extern FILE    *terminal;      /* file descriptor for the terminal input */
+extern int     pipein;         /* input is from a pipe */
+extern char    *tmpdir;        /* name of temp directory */
+extern int     oldinofmt;      /* reading tape with old format inodes */
+extern int     Bcvt;           /* need byte swapping on inodes and dirs */
+extern int     compare_ignore_not_found;
+                               /* used to compare incremental dumps, */
+                               /* so messages about "not found" files */
+                               /* isn't seen. */
+extern int     compare_errors; /* did we encounter any compare errors? */
+extern char    filesys[NAMELEN];/* name of dumped filesystem */
+extern dump_ino_t volinfo[];   /* which inode on which volume archive info */
+
+/*
+ * Each file in the file system is described by one of these entries
+ */
+struct entry {
+       char    *e_name;                /* the current name of this entry */
+       u_char  e_namlen;               /* length of this name */
+       char    e_type;                 /* type of this entry, see below */
+       short   e_flags;                /* status flags, see below */
+       dump_ino_t e_ino;               /* inode number in previous file sys */
+       long    e_index;                /* unique index (for dumpped table) */
+       struct  entry *e_parent;        /* pointer to parent directory (..) */
+       struct  entry *e_sibling;       /* next element in this directory (.) */
+       struct  entry *e_links;         /* hard links to this inode */
+       struct  entry *e_entries;       /* for directories, their entries */
+       struct  entry *e_next;          /* hash chain list */
+};
+/* types */
+#define        LEAF 1                  /* non-directory entry */
+#define NODE 2                 /* directory entry */
+#define LINK 4                 /* synthesized type, stripped by addentry */
+/* flags */
+#define EXTRACT                0x0001  /* entry is to be replaced from the tape */
+#define NEW            0x0002  /* a new entry to be extracted */
+#define KEEP           0x0004  /* entry is not to change */
+#define REMOVED                0x0010  /* entry has been removed */
+#define TMPNAME                0x0020  /* entry has been given a temporary name */
+#define EXISTED                0x0040  /* directory already existed during extract */
+
+/*
+ * Constants associated with entry structs
+ */
+#define HARDLINK       1
+#define SYMLINK                2
+#define TMPHDR         "RSTTMP"
+
+/*
+ * The entry describes the next file available on the tape
+ */
+struct context {
+       char    *name;          /* name of file */
+       dump_ino_t ino;         /* inumber of file */
+#if defined(__linux__) || defined(sunos)
+       struct  new_bsd_inode *dip;     /* pointer to inode */
+#else
+       struct  dinode *dip;    /* pointer to inode */
+#endif
+       char    action;         /* action being taken on this file */
+} curfile;
+/* actions */
+#define        USING   1       /* extracting from the tape */
+#define        SKIP    2       /* skipping */
+#define UNKNOWN 3      /* disposition or starting point is unknown */
+
+/*
+ * Definitions for library routines operating on directories.
+ */
+typedef struct rstdirdesc RST_DIR;
+
+/*
+ * Flags to setdirmodes.
+ */
+#define FORCE  0x0001
+
+/*
+ * Useful macros
+ */
+#define TSTINO(ino, map) \
+       (map[(u_int)((ino) - 1) / NBBY] &  (1 << ((u_int)((ino) - 1) % NBBY)))
+#define        SETINO(ino, map) \
+       map[(u_int)((ino) - 1) / NBBY] |=  1 << ((u_int)((ino) - 1) % NBBY)
+
+#define Dprintf                if (dflag) fprintf
+#define Vprintf                if (vflag) fprintf
+
+#define GOOD 1
+#define FAIL 0
+
+#ifdef USE_QFA
+#define QFA_MAGIC      "495115637697"
+#define QFA_VERSION    "1.0"
+extern FILE    *gTapeposfp;
+extern char    *gTapeposfile;
+extern char    gTps[255];
+extern long    gSeekstart;
+extern int     tapeposflag;
+extern int     gTapeposfd;
+extern int     createtapeposflag;
+extern unsigned long qfadumpdate;
+extern long long curtapepos;
+#ifdef sunos
+int            fdsmtc;
+long   scsiid;
+char   smtcpath[2048];
+#endif
+#endif /* USE_QFA */
+
+#define do_compare_error \
+       if (++compare_errors >= Lflag && Lflag) { \
+               printf("Compare errors limit reached, exiting...\n"); \
+               exit(2); \
+       }
+
diff --git a/restore/symtab.c b/restore/symtab.c
new file mode 100644 (file)
index 0000000..3e6d3fc
--- /dev/null
@@ -0,0 +1,639 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: symtab.c,v 1.22 2003/10/26 16:05:48 stelian Exp $";
+#endif /* not lint */
+
+/*
+ * These routines maintain the symbol table which tracks the state
+ * of the file system being restored. They provide lookup by either
+ * name or inode number. They also provide for creation, deletion,
+ * and renaming of entries. Because of the dynamic nature of pathnames,
+ * names should not be saved, but always constructed just before they
+ * are needed, by calling "myname".
+ */
+
+#include <config.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#include <sys/time.h>
+#include <time.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <bsdcompat.h>
+#else  /* __linux__ */
+#ifdef sunos
+#include <sys/fcntl.h>
+#include <bsdcompat.h>
+#else
+#include <ufs/ufs/dinode.h>
+#endif
+#endif /* __linux__ */
+
+#include <errno.h>
+#include <compaterr.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "restore.h"
+#include "extern.h"
+
+/*
+ * The following variables define the inode symbol table.
+ * The primary hash table is dynamically allocated based on
+ * the number of inodes in the file system (maxino), scaled by
+ * HASHFACTOR. The variable "entry" points to the hash table;
+ * the variable "entrytblsize" indicates its size (in entries).
+ */
+#define HASHFACTOR 5
+static struct entry **entry;
+static long entrytblsize;
+
+static void             addino __P((dump_ino_t, struct entry *));
+static struct entry    *lookupparent __P((char *));
+static void             removeentry __P((struct entry *));
+
+/*
+ * Look up an entry by inode number
+ */
+struct entry *
+lookupino(dump_ino_t inum)
+{
+       struct entry *ep;
+
+       if (inum < WINO || inum >= maxino)
+               return (NULL);
+       for (ep = entry[inum % entrytblsize]; ep != NULL; ep = ep->e_next)
+               if (ep->e_ino == inum)
+                       return (ep);
+       return (NULL);
+}
+
+/*
+ * Add an entry into the entry table
+ */
+static void
+addino(dump_ino_t inum, struct entry *np)
+{
+       struct entry **epp;
+
+       if (inum < WINO || inum >= maxino)
+               panic("addino: out of range %d\n", inum);
+       epp = &entry[inum % entrytblsize];
+       np->e_ino = inum;
+       np->e_next = *epp;
+       *epp = np;
+       if (dflag)
+               for (np = np->e_next; np != NULL; np = np->e_next)
+                       if (np->e_ino == inum)
+                               badentry(np, "duplicate inum");
+}
+
+/*
+ * Delete an entry from the entry table
+ */
+void
+deleteino(dump_ino_t inum)
+{
+       struct entry *next;
+       struct entry **prev;
+
+       if (inum < WINO || inum >= maxino)
+               panic("deleteino: out of range %d\n", inum);
+       prev = &entry[inum % entrytblsize];
+       for (next = *prev; next != NULL; next = next->e_next) {
+               if (next->e_ino == inum) {
+                       next->e_ino = 0;
+                       *prev = next->e_next;
+                       return;
+               }
+               prev = &next->e_next;
+       }
+       panic("deleteino: %d not found\n", inum);
+}
+
+/*
+ * Look up an entry by name
+ */
+struct entry *
+lookupname(char *name)
+{
+       struct entry *ep;
+       char *np, *cp;
+       char buf[MAXPATHLEN];
+
+       cp = name;
+       for (ep = lookupino(ROOTINO); ep != NULL; ep = ep->e_entries) {
+               for (np = buf; *cp != '/' && *cp != '\0' &&
+                               np < &buf[sizeof(buf)]; )
+                       *np++ = *cp++;
+               if (np == &buf[sizeof(buf)])
+                       break;
+               *np = '\0';
+               for ( ; ep != NULL; ep = ep->e_sibling)
+                       if (strcmp(ep->e_name, buf) == 0)
+                               break;
+               if (ep == NULL)
+                       break;
+               if (*cp++ == '\0')
+                       return (ep);
+       }
+       return (NULL);
+}
+
+/*
+ * Look up the parent of a pathname
+ */
+static struct entry *
+lookupparent(char *name)
+{
+       struct entry *ep;
+       char *tailindex;
+
+       tailindex = strrchr(name, '/');
+       if (tailindex == NULL)
+               return (NULL);
+       *tailindex = '\0';
+       ep = lookupname(name);
+       *tailindex = '/';
+       if (ep == NULL)
+               return (NULL);
+       if (ep->e_type != NODE)
+               panic("%s is not a directory\n", name);
+       return (ep);
+}
+
+/*
+ * Determine the current pathname of a node or leaf
+ */
+char *
+myname(struct entry *ep)
+{
+       char *cp;
+       static char namebuf[MAXPATHLEN];
+
+       for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) {
+               cp -= ep->e_namlen;
+               memmove(cp, ep->e_name, (size_t)ep->e_namlen);
+               if (ep == lookupino(ROOTINO))
+                       return (cp);
+               *(--cp) = '/';
+               ep = ep->e_parent;
+       }
+       panic("%s: pathname too long\n", cp);
+       return(cp);
+}
+
+/*
+ * Unused symbol table entries are linked together on a free list
+ * headed by the following pointer.
+ */
+static struct entry *freelist = NULL;
+
+/*
+ * add an entry to the symbol table
+ */
+struct entry *
+addentry(char *name, dump_ino_t inum, int type)
+{
+       struct entry *np, *ep;
+
+       if (freelist != NULL) {
+               np = freelist;
+               freelist = np->e_next;
+               memset(np, 0, sizeof(struct entry));
+       } else {
+               np = (struct entry *)calloc(1, sizeof(struct entry));
+               if (np == NULL)
+                       errx(1, "no memory to extend symbol table");
+       }
+       np->e_type = type & ~LINK;
+       ep = lookupparent(name);
+       if (ep == NULL) {
+               if (inum != ROOTINO || lookupino(ROOTINO) != NULL)
+                       panic("bad name to addentry %s\n", name);
+               np->e_name = savename(name);
+               np->e_namlen = strlen(name);
+               np->e_parent = np;
+               addino(ROOTINO, np);
+               return (np);
+       }
+       np->e_name = savename(strrchr(name, '/') + 1);
+       np->e_namlen = strlen(np->e_name);
+       np->e_parent = ep;
+       np->e_sibling = ep->e_entries;
+       ep->e_entries = np;
+       if (type & LINK) {
+               ep = lookupino(inum);
+               if (ep == NULL)
+                       panic("link to non-existent name\n");
+               np->e_ino = inum;
+               np->e_links = ep->e_links;
+               ep->e_links = np;
+       } else if (inum != 0) {
+               if (lookupino(inum) != NULL)
+                       panic("duplicate entry\n");
+               addino(inum, np);
+       }
+       return (np);
+}
+
+/*
+ * delete an entry from the symbol table
+ */
+void
+freeentry(struct entry *ep)
+{
+       struct entry *np;
+       dump_ino_t inum;
+
+       if (ep->e_flags != REMOVED)
+               badentry(ep, "not marked REMOVED");
+       if (ep->e_type == NODE) {
+               if (ep->e_links != NULL)
+                       badentry(ep, "freeing referenced directory");
+               if (ep->e_entries != NULL)
+                       badentry(ep, "freeing non-empty directory");
+       }
+       if (ep->e_ino != 0) {
+               np = lookupino(ep->e_ino);
+               if (np == NULL)
+                       badentry(ep, "lookupino failed");
+               if (np == ep) {
+                       inum = ep->e_ino;
+                       deleteino(inum);
+                       if (ep->e_links != NULL)
+                               addino(inum, ep->e_links);
+               } else {
+                       for (; np != NULL; np = np->e_links) {
+                               if (np->e_links == ep) {
+                                       np->e_links = ep->e_links;
+                                       break;
+                               }
+                       }
+                       if (np == NULL)
+                               badentry(ep, "link not found");
+               }
+       }
+       removeentry(ep);
+       freename(ep->e_name);
+       ep->e_next = freelist;
+       freelist = ep;
+}
+
+/*
+ * Relocate an entry in the tree structure
+ */
+void
+moveentry(struct entry *ep, char *newname)
+{
+       struct entry *np;
+       char *cp;
+
+       np = lookupparent(newname);
+       if (np == NULL)
+               badentry(ep, "cannot move ROOT");
+       if (np != ep->e_parent) {
+               removeentry(ep);
+               ep->e_parent = np;
+               ep->e_sibling = np->e_entries;
+               np->e_entries = ep;
+       }
+       cp = strrchr(newname, '/') + 1;
+       freename(ep->e_name);
+       ep->e_name = savename(cp);
+       ep->e_namlen = strlen(cp);
+       if (strcmp(gentempname(ep), ep->e_name) == 0)
+               ep->e_flags |= TMPNAME;
+       else
+               ep->e_flags &= ~TMPNAME;
+}
+
+/*
+ * Remove an entry in the tree structure
+ */
+static void
+removeentry(struct entry *ep)
+{
+       struct entry *np;
+
+       np = ep->e_parent;
+       if (np->e_entries == ep) {
+               np->e_entries = ep->e_sibling;
+       } else {
+               for (np = np->e_entries; np != NULL; np = np->e_sibling) {
+                       if (np->e_sibling == ep) {
+                               np->e_sibling = ep->e_sibling;
+                               break;
+                       }
+               }
+               if (np == NULL)
+                       badentry(ep, "cannot find entry in parent list");
+       }
+}
+
+/*
+ * Table of unused string entries, sorted by length.
+ *
+ * Entries are allocated in STRTBLINCR sized pieces so that names
+ * of similar lengths can use the same entry. The value of STRTBLINCR
+ * is chosen so that every entry has at least enough space to hold
+ * a "struct strtbl" header. Thus every entry can be linked onto an
+ * appropriate free list.
+ *
+ * NB. The macro "allocsize" below assumes that "struct strhdr"
+ *     has a size that is a power of two.
+ */
+struct strhdr {
+       struct strhdr *next;
+};
+
+#define STRTBLINCR     (sizeof(struct strhdr))
+#define allocsize(size)        (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
+
+static struct strhdr strtblhdr[allocsize(MAXNAMLEN) / STRTBLINCR];
+
+/*
+ * Allocate space for a name. It first looks to see if it already
+ * has an appropriate sized entry, and if not allocates a new one.
+ */
+char *
+savename(char *name)
+{
+       struct strhdr *np;
+       long len;
+       char *cp;
+
+       if (name == NULL)
+               panic("bad name\n");
+       len = strlen(name);
+       np = strtblhdr[len / STRTBLINCR].next;
+       if (np != NULL) {
+               strtblhdr[len / STRTBLINCR].next = np->next;
+               cp = (char *)np;
+       } else {
+               cp = malloc((unsigned)allocsize(len));
+               if (cp == NULL)
+                       errx(1, "no space for string table");
+       }
+       (void) strcpy(cp, name);
+       return (cp);
+}
+
+/*
+ * Free space for a name. The resulting entry is linked onto the
+ * appropriate free list.
+ */
+void
+freename(char *name)
+{
+       struct strhdr *tp, *np;
+
+       tp = &strtblhdr[strlen(name) / STRTBLINCR];
+       np = (struct strhdr *)name;
+       np->next = tp->next;
+       tp->next = np;
+}
+
+/*
+ * Useful quantities placed at the end of a dumped symbol table.
+ */
+struct symtableheader {
+       int32_t volno;
+       int32_t stringsize;
+       int32_t entrytblsize;
+       time_t  dumptime;
+       time_t  dumpdate;
+       dump_ino_t maxino;
+       int32_t ntrec;
+       int32_t zflag;
+};
+
+/*
+ * dump a snapshot of the symbol table
+ */
+void
+dumpsymtable(char *filename, long checkpt)
+{
+       struct entry *ep, *tep;
+       dump_ino_t i;
+       struct entry temp, *tentry;
+       long mynum = 1, stroff = 0;
+       FILE *fd;
+       struct symtableheader hdr;
+
+       Vprintf(stdout, "Check pointing the restore\n");
+       if (Nflag)
+               return;
+       if ((fd = fopen(filename, "w")) == NULL) {
+               warn("fopen");
+               panic("cannot create save file %s for symbol table\n",
+                       filename);
+       }
+       clearerr(fd);
+       /*
+        * Assign indices to each entry
+        * Write out the string entries
+        */
+       for (i = WINO; i <= maxino; i++) {
+               for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
+                       ep->e_index = mynum++;
+                       (void) fwrite(ep->e_name, sizeof(char),
+                              (int)allocsize(ep->e_namlen), fd);
+               }
+       }
+       /*
+        * Convert pointers to indexes, and output
+        */
+       tep = &temp;
+       stroff = 0;
+       for (i = WINO; i <= maxino; i++) {
+               for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
+                       memmove(tep, ep, sizeof(struct entry));
+                       tep->e_name = (char *)stroff;
+                       stroff += allocsize(ep->e_namlen);
+                       tep->e_parent = (struct entry *)ep->e_parent->e_index;
+                       if (ep->e_links != NULL)
+                               tep->e_links =
+                                       (struct entry *)ep->e_links->e_index;
+                       if (ep->e_sibling != NULL)
+                               tep->e_sibling =
+                                       (struct entry *)ep->e_sibling->e_index;
+                       if (ep->e_entries != NULL)
+                               tep->e_entries =
+                                       (struct entry *)ep->e_entries->e_index;
+                       if (ep->e_next != NULL)
+                               tep->e_next =
+                                       (struct entry *)ep->e_next->e_index;
+                       (void) fwrite((char *)tep, sizeof(struct entry), 1, fd);
+               }
+       }
+       /*
+        * Convert entry pointers to indexes, and output
+        */
+       for (i = 0; (long)i < entrytblsize; i++) {
+               if (entry[i] == NULL)
+                       tentry = NULL;
+               else
+                       tentry = (struct entry *)entry[i]->e_index;
+               (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd);
+       }
+       hdr.volno = checkpt;
+       hdr.maxino = maxino;
+       hdr.entrytblsize = entrytblsize;
+       hdr.stringsize = stroff;
+       hdr.dumptime = dumptime;
+       hdr.dumpdate = dumpdate;
+       hdr.ntrec = ntrec;
+       hdr.zflag = zflag;
+       (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
+       if (ferror(fd)) {
+               warn("fwrite");
+               panic("output error to file %s writing symbol table\n",
+                       filename);
+       }
+       (void) fclose(fd);
+}
+
+/*
+ * Initialize a symbol table from a file
+ */
+void
+initsymtable(char *filename)
+{
+       char *base;
+       long tblsize;
+       struct entry *ep;
+       struct entry *baseep, *lep;
+       struct symtableheader hdr;
+       struct stat stbuf;
+       long i;
+       int fd;
+
+       Vprintf(stdout, "Initialize symbol table.\n");
+       if (filename == NULL) {
+               entrytblsize = maxino / HASHFACTOR;
+               entry = (struct entry **)
+                       calloc((unsigned)entrytblsize, sizeof(struct entry *));
+               if (entry == (struct entry **)NULL)
+                       errx(1, "no memory for entry table");
+               ep = addentry(".", ROOTINO, NODE);
+               ep->e_flags |= NEW;
+               return;
+       }
+       if ((fd = open(filename, O_RDONLY, 0)) < 0) {
+               warn("open");
+               errx(1, "cannot open symbol table file %s", filename);
+       }
+       if (fstat(fd, &stbuf) < 0) {
+               warn("stat");
+               errx(1, "cannot stat symbol table file %s", filename);
+       }
+       tblsize = stbuf.st_size - sizeof(struct symtableheader);
+       base = calloc(sizeof(char), (unsigned)tblsize);
+       if (base == NULL)
+               errx(1, "cannot allocate space for symbol table");
+       if (read(fd, base, (int)tblsize) < 0 ||
+           read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) {
+               warn("read");
+               errx(1, "cannot read symbol table file %s", filename);
+       }
+       switch (command) {
+       case 'r':
+               /*
+                * For normal continuation, insure that we are using
+                * the next incremental tape
+                */
+               if (hdr.dumpdate != dumptime)
+                       errx(1, "Incremental tape too %s",
+                               (hdr.dumpdate < dumptime) ? "low" : "high");
+               break;
+       case 'R':
+               /*
+                * For restart, insure that we are using the same tape
+                */
+               curfile.action = SKIP;
+               dumptime = hdr.dumptime;
+               dumpdate = hdr.dumpdate;
+               zflag = hdr.zflag;
+               if (!bflag)
+                       newtapebuf(hdr.ntrec);
+               getvol(hdr.volno);
+               break;
+       default:
+               panic("initsymtable called from command %c\n", command);
+               break;
+       }
+       resizemaps(maxino, hdr.maxino);
+       maxino = hdr.maxino;
+       entrytblsize = hdr.entrytblsize;
+       entry = (struct entry **)
+               (base + tblsize - (entrytblsize * sizeof(struct entry *)));
+       baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry));
+       lep = (struct entry *)entry;
+       for (i = 0; i < entrytblsize; i++) {
+               if (entry[i] == NULL)
+                       continue;
+               entry[i] = &baseep[(long)entry[i]];
+       }
+       for (ep = &baseep[1]; ep < lep; ep++) {
+               ep->e_name = base + (long)ep->e_name;
+               ep->e_parent = &baseep[(long)ep->e_parent];
+               if (ep->e_sibling != NULL)
+                       ep->e_sibling = &baseep[(long)ep->e_sibling];
+               if (ep->e_links != NULL)
+                       ep->e_links = &baseep[(long)ep->e_links];
+               if (ep->e_entries != NULL)
+                       ep->e_entries = &baseep[(long)ep->e_entries];
+               if (ep->e_next != NULL)
+                       ep->e_next = &baseep[(long)ep->e_next];
+       }
+}
diff --git a/restore/tape.c b/restore/tape.c
new file mode 100644 (file)
index 0000000..2f344db
--- /dev/null
@@ -0,0 +1,3122 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: tape.c,v 1.81 2004/05/25 10:39:31 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <compatlfs.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <compaterr.h>
+#include <system.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/mtio.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#include <sys/time.h>
+#include <time.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>
+#include <bsdcompat.h>
+#else  /* __linux__ */
+#ifdef sunos
+#define quad_t int64_t
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <bsdcompat.h>
+#else
+#include <ufs/ufs/dinode.h>
+#endif
+#endif /* __linux__ */
+#ifdef DUMP_MACOSX
+#include "darwin.h"
+#endif
+#include <protocols/dumprestore.h>
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif /* HAVE_ZLIB */
+
+#ifdef HAVE_BZLIB
+#include <bzlib.h>
+#endif /* HAVE_BZLIB */
+
+#ifdef HAVE_LZO
+#include <minilzo.h>
+#endif /* HAVE_LZO */
+
+#include "restore.h"
+#include "extern.h"
+#include "pathnames.h"
+
+#ifdef USE_QFA
+int            noresyncmesg = 0;
+#endif /* USE_QFA */
+static long    fssize = MAXBSIZE;
+static int     mt = -1;
+int            pipein = 0;
+static int     magtapein = 0;          /* input is from magtape */
+static char    magtape[MAXPATHLEN];
+static char    magtapeprefix[MAXPATHLEN];
+static int     blkcnt;
+static int     numtrec;
+static char    *tapebuf;               /* input buffer for read */
+static int     bufsize;                /* buffer size without prefix */
+static char    *tbufptr = NULL;        /* active tape buffer */
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+static char    *comprbuf;              /* uncompress work buf */
+static size_t  comprlen;               /* size including prefix */
+#endif
+static union   u_spcl endoftapemark;
+static long    blksread;               /* blocks read since last header */
+static long    tpblksread = 0;         /* TP_BSIZE blocks read */
+static long    tapesread;
+static sigjmp_buf      restart;
+static int     gettingfile = 0;        /* restart has a valid frame */
+char           *host = NULL;
+
+static int     ofile;
+static char    *map;
+static char    lnkbuf[MAXPATHLEN + 1];
+static int     pathlen;
+
+int            oldinofmt;      /* old inode format conversion required */
+int            Bcvt;           /* Swap Bytes (for CCI or sun) */
+static int     Qcvt;           /* Swap quads (for sun) */
+
+#define        FLUSHTAPEBUF()  blkcnt = ntrec + 1
+
+static void     accthdr __P((struct s_spcl *));
+static int      checksum __P((int *));
+static void     findinode __P((struct s_spcl *));
+static void     findtapeblksize __P((void));
+static int      gethead __P((struct s_spcl *));
+static int      converthead __P((struct s_spcl *));
+static void     converttapebuf __P((struct tapebuf *));
+static void     readtape __P((char *));
+static void     setdumpnum __P((void));
+#ifdef DUMP_MACOSX
+static void     xtrfilefinderinfo __P((char *, size_t));
+#endif
+
+static u_int    swabi __P((u_int));
+#if 0
+static u_long   swabl __P((u_long));
+#endif
+static u_char  *swab64 __P((u_char *, int));
+static u_char  *swab32 __P((u_char *, int));
+static u_char  *swab16 __P((u_char *, int));
+static void     terminateinput __P((void));
+static void     xtrfile __P((char *, size_t));
+static void     xtrlnkfile __P((char *, size_t));
+static void     xtrlnkskip __P((char *, size_t));
+static void     xtrmap __P((char *, size_t));
+static void     xtrmapskip __P((char *, size_t));
+static void     xtrskip __P((char *, size_t));
+static void     setmagtapein __P((void));
+
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+static void    newcomprbuf __P((int));
+static void    (*readtape_func) __P((char *));
+static void    readtape_set __P((char *));
+static void    readtape_uncompr __P((char *));
+static void    readtape_comprfile __P((char *));
+static void    readtape_comprtape __P((char *));
+static char    *decompress_tapebuf __P((struct tapebuf *, int));
+static void    msg_read_error __P((char *));
+#endif
+static int     read_a_block __P((int, char *, size_t, long *));
+#define PREFIXSIZE     sizeof(struct tapebuf)
+
+#define COMPARE_ONTHEFLY 1
+
+#if COMPARE_ONTHEFLY
+static int     ifile;          /* input file for compare */
+static int     cmperror;       /* compare error */
+static void    xtrcmpfile __P((char *, size_t));
+static void    xtrcmpskip __P((char *, size_t));
+#endif
+
+static int readmapflag;
+static int readingmaps;                /* set to 1 while reading the maps */
+
+#ifdef DUMP_MACOSX
+static DumpFinderInfo  gFndrInfo;
+#endif
+
+/*
+ * Set up an input source. This is called from main.c before setup() is.
+ */
+void
+setinput(char *source)
+{
+       int i;
+       char *n;
+
+       FLUSHTAPEBUF();
+       if (bflag)
+               newtapebuf(ntrec);
+       else
+               newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
+       terminal = stdin;
+
+#ifdef RRESTORE
+       if ((n = strchr(source, ':'))) {
+               for (i = 0; i < (n - source); i++) {
+                       if (source[i] == '/')
+                               break;
+               }
+               if (source[i] != '/') {
+                       host = source;
+                       source = strchr(host, ':');
+                       *source++ = '\0';
+                       if (rmthost(host) == 0)
+                               exit(1);
+               }
+       } else
+#endif
+       if (strcmp(source, "-") == 0) {
+               /*
+                * Since input is coming from a pipe we must establish
+                * our own connection to the terminal.
+                */
+               terminal = fopen(_PATH_TTY, "r");
+               if (terminal == NULL) {
+                       warn("cannot open %s", _PATH_TTY);
+                       terminal = fopen(_PATH_DEVNULL, "r");
+                       if (terminal == NULL)
+                               err(1, "cannot open %s", _PATH_DEVNULL);
+               }
+               pipein++;
+       }
+       setuid(getuid());       /* no longer need or want root privileges */
+       if (Mflag) {
+               strncpy(magtapeprefix, source, MAXPATHLEN);
+               magtapeprefix[MAXPATHLEN-1] = '\0';
+               snprintf(magtape, MAXPATHLEN, "%s%03d", source, 1);
+       }
+       else
+               strncpy(magtape, source, MAXPATHLEN);
+       magtape[MAXPATHLEN - 1] = '\0';
+}
+
+void
+newtapebuf(long size)
+{
+       static int tapebufsize = -1;
+
+       ntrec = size;
+       bufsize = ntrec * TP_BSIZE;
+       if (size <= tapebufsize)
+               return;
+       if (tapebuf != NULL)
+               free(tapebuf);
+       tapebuf = malloc(size * TP_BSIZE + sizeof(struct tapebuf));
+       if (tapebuf == NULL)
+               errx(1, "Cannot allocate space for tape buffer");
+       tapebufsize = size;
+}
+
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+static void
+newcomprbuf(int size)
+{
+       size_t buf_size = (size+1) * TP_BSIZE + sizeof(struct tapebuf);
+       if (buf_size <= comprlen)
+               return;
+       comprlen = buf_size;
+       if (comprbuf != NULL)
+               free(comprbuf);
+       comprbuf = malloc(comprlen);
+       if (comprbuf == NULL)
+               errx(1, "Cannot allocate space for decompress buffer");
+}
+#endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
+
+/*
+ * Verify that the tape drive can be accessed and
+ * that it actually is a dump tape.
+ */
+void
+setup(void)
+{
+       int i, j, *ip, bot_code;
+       struct STAT stbuf;
+       char *temptape;
+
+       Vprintf(stdout, "Verify tape and initialize maps\n");
+       if (Afile == NULL && bot_script) {
+               msg("Launching %s\n", bot_script);
+               bot_code = system_command(bot_script, magtape, 1);
+               if (bot_code != 0 && bot_code != 1) {
+                       msg("Restore aborted by the beginning of tape script\n");
+                       exit(1);
+               }
+       }
+
+       if (Afile)
+               temptape = Afile;
+       else
+               temptape = magtape;
+
+#ifdef RRESTORE
+       if (!Afile && host)
+               mt = rmtopen(temptape, O_RDONLY);
+       else
+#endif
+       if (pipein)
+               mt = 0;
+       else
+               mt = OPEN(temptape, O_RDONLY, 0);
+       if (mt < 0)
+               err(1, "%s", temptape);
+       if (!Afile) {
+               volno = 1;
+               setmagtapein();
+               setdumpnum();
+       }
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+       readtape_func = readtape_set;
+#if defined(HAVE_LZO)
+       if (lzo_init() != LZO_E_OK) {
+         msg("internal error - lzo_init failed \n");
+         exit(1);
+        }
+#endif
+#endif
+       FLUSHTAPEBUF();
+       findtapeblksize();
+       if (gethead(&spcl) == FAIL) {
+               blkcnt--; /* push back this block */
+               blksread--;
+               tpblksread--;
+               cvtflag++;
+               if (gethead(&spcl) == FAIL)
+                       errx(1, "Tape is not a dump tape");
+               fprintf(stderr, "Converting to new file system format.\n");
+       }
+
+       if (zflag) {
+               fprintf(stderr, "Dump tape is compressed.\n");
+#if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB) && !defined(HAVE_LZO)
+               errx(1,"This restore version doesn't support decompression");
+#endif /* !HAVE_ZLIB && !HAVE_BZLIB */
+       }
+       if (pipein) {
+               endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
+               endoftapemark.s_spcl.c_type = TS_END;
+               ip = (int *)&endoftapemark;
+               j = sizeof(union u_spcl) / sizeof(int);
+               i = 0;
+               do
+                       i += *ip++;
+               while (--j);
+               endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
+       }
+       if (vflag || command == 't' || command == 'C')
+               printdumpinfo();
+#ifdef USE_QFA
+       if (tapeposflag && (unsigned long)spcl.c_date != qfadumpdate)
+               errx(1, "different QFA/dumpdates detected\n");
+#endif
+       if (filesys[0] == '\0') {
+               char *dirptr;
+               strncpy(filesys, spcl.c_filesys, NAMELEN);
+               filesys[NAMELEN - 1] = '\0';
+               dirptr = strstr(filesys, " (dir");
+               if (dirptr != NULL)
+                       *dirptr = '\0';
+       }
+       dumptime = spcl.c_ddate;
+       dumpdate = spcl.c_date;
+       if (STAT(".", &stbuf) < 0)
+               err(1, "cannot stat .");
+       if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
+               fssize = TP_BSIZE;
+       if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
+               fssize = stbuf.st_blksize;
+       if (((fssize - 1) & fssize) != 0)
+               errx(1, "bad block size %ld", fssize);
+       if (spcl.c_volume != 1)
+               errx(1, "Tape is not volume 1 of the dump");
+       if (gethead(&spcl) == FAIL) {
+               Dprintf(stdout, "header read failed at %ld blocks\n", (long)blksread);
+               panic("no header after volume mark!\n");
+       }
+       readingmaps = 1;
+       findinode(&spcl);
+       if (spcl.c_type != TS_CLRI)
+               errx(1, "Cannot find file removal list");
+       maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
+       map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
+       if (map == NULL)
+               errx(1, "no memory for active inode map");
+       usedinomap = map;
+       curfile.action = USING;
+       getfile(xtrmap, xtrmapskip);
+       while (spcl.c_type == TS_ADDR) {
+               /* Recompute maxino and the map */
+               dump_ino_t oldmaxino = maxino;
+               maxino += (spcl.c_count * TP_BSIZE * NBBY) + 1;
+               resizemaps(oldmaxino, maxino);
+               map = usedinomap;
+
+               spcl.c_dinode.di_size = spcl.c_count * TP_BSIZE;
+               getfile(xtrmap, xtrmapskip);
+       }
+       Dprintf(stdout, "maxino = %lu\n", (unsigned long)maxino);
+       if (spcl.c_type != TS_BITS) {
+               if (spcl.c_type == TS_END) {
+                       msg("Cannot find file dump list, assuming empty tape\n");
+                       exit(0);
+               }
+               errx(1, "Cannot find file dump list");
+       }
+       map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
+       if (map == (char *)NULL)
+               errx(1, "no memory for file dump list");
+       dumpmap = map;
+       curfile.action = USING;
+       getfile(xtrmap, xtrmapskip);
+       while (spcl.c_type == TS_ADDR) {
+               spcl.c_dinode.di_size = spcl.c_count * TP_BSIZE;
+               getfile(xtrmap, xtrmapskip);
+       }
+       /*
+        * If there may be whiteout entries on the tape, pretend that the
+        * whiteout inode exists, so that the whiteout entries can be
+        * extracted.
+        */
+       if (oldinofmt == 0)
+               SETINO(WINO, dumpmap);
+       readingmaps = 0;
+       findinode(&spcl);
+}
+
+/*
+ * Prompt user to load a new dump volume.
+ * "Nextvol" is the next suggested volume to use.
+ * This suggested volume is enforced when doing full
+ * or incremental restores, but can be overridden by
+ * the user when only extracting a subset of the files.
+ */
+void
+getvol(long nextvol)
+{
+       long newvol = 0, wantnext = 0, i;
+       long saved_blksread = 0, saved_tpblksread = 0;
+       union u_spcl tmpspcl;
+#      define tmpbuf tmpspcl.s_spcl
+       char buf[TP_BSIZE];
+       int haderror = 0, bot_code = 1;
+
+       if (nextvol == 1) {
+               tapesread = 0;
+               gettingfile = 0;
+               tpblksread = 0;
+               blksread = 0;
+       }
+       if (pipein) {
+               if (nextvol != 1)
+                       panic("Changing volumes on pipe input?\n");
+               if (volno == 1)
+                       return;
+               goto gethdr;
+       }
+       saved_blksread = blksread;
+       saved_tpblksread = tpblksread;
+#if defined(USE_QFA) && defined(sunos)
+       if (createtapeposflag || tapeposflag) 
+               close(fdsmtc);
+#endif
+again:
+       if (pipein)
+               exit(1); /* pipes do not get a second chance */
+       if (aflag || curfile.action != SKIP) {
+               newvol = nextvol;
+               wantnext = 1;
+       } else {
+               newvol = 0;
+               wantnext = 0;
+       }
+       while (newvol <= 0) {
+               if (tapesread == 0) {
+                       fprintf(stderr, "%s%s%s%s%s",
+                           "You have not read any volumes yet.\n",
+                           "Unless you know which volume your",
+                           " file(s) are on you should start\n",
+                           "with the last volume and work",
+                           " towards the first.\n");
+               } else {
+                       fprintf(stderr, "You have read volumes");
+                       strcpy(buf, ": ");
+                       for (i = 1; i < 32; i++)
+                               if (tapesread & (1 << i)) {
+                                       fprintf(stderr, "%s%ld", buf, (long)i);
+                                       strcpy(buf, ", ");
+                               }
+                       fprintf(stderr, "\n");
+               }
+               do      {
+                       fprintf(stderr, "Specify next volume # (none if no more volumes): ");
+                       (void) fflush(stderr);
+                       (void) fgets(buf, TP_BSIZE, terminal);
+               } while (!feof(terminal) && buf[0] == '\n');
+               if (feof(terminal))
+                       exit(1);
+               if (!strcmp(buf, "none\n")) {
+                       terminateinput();
+                       return;
+               }
+               newvol = atoi(buf);
+               if (newvol <= 0) {
+                       fprintf(stderr,
+                           "Volume numbers are positive numerics\n");
+               }
+       }
+       if (newvol == volno) {
+               tapesread |= 1 << volno;
+#if defined(USE_QFA) && defined(sunos)
+               if (createtapeposflag || tapeposflag) {
+                       if (OpenSMTCmt(magtape) < 0) {
+                               volno = -1;
+                               haderror = 1;
+                               goto again;
+                       }
+               }
+#endif /* USE_QFA */
+               return;
+       }
+       closemt();
+
+       /* 
+        * if using an archive file, reset its name so readtape()
+        * could properly use remote access.
+        */
+       Afile = NULL;
+
+       if (Mflag) {
+               snprintf(magtape, MAXPATHLEN, "%s%03ld", magtapeprefix, newvol);
+               magtape[MAXPATHLEN - 1] = '\0';
+       }
+       if (bot_script && !haderror) {
+               msg("Launching %s\n", bot_script);
+               bot_code = system_command(bot_script, magtape, newvol);
+               if (bot_code != 0 && bot_code != 1) {
+                       msg("Restore aborted by the beginning of tape script\n");
+                       exit(1);
+               }
+       }
+       if (haderror || (bot_code && !Mflag)) {
+               haderror = 0;
+#ifdef sunos
+               fprintf(stderr, "Mount volume %ld\n", (long)newvol);
+#else
+               fprintf(stderr, "Mount tape volume %ld\n", (long)newvol);
+#endif
+               fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
+#ifdef sunos
+               fprintf(stderr, "then enter volume name (default: %s) ", magtape);
+#else
+               fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
+#endif
+               (void) fflush(stderr);
+               (void) fgets(buf, TP_BSIZE, terminal);
+               if (feof(terminal))
+                       exit(1);
+               if (!strcmp(buf, "none\n")) {
+                       terminateinput();
+                       return;
+               }
+               if (buf[0] != '\n') {
+                       char *pos;
+                       (void) strncpy(magtape, buf, sizeof(magtape));
+                       magtape[sizeof(magtape) - 1] = '\0';
+                       if ((pos = strchr(magtape, '\n'))) 
+                               magtape[pos - magtape] = '\0';
+               }
+       }
+#if defined(USE_QFA) && defined(sunos)
+       if (createtapeposflag || tapeposflag) {
+               if (OpenSMTCmt(magtape) < 0) {
+                       volno = -1;
+                       haderror = 1;
+                       goto again;
+               }
+       }
+#endif /* USE_QFA */
+#ifdef RRESTORE
+       if (host)
+               mt = rmtopen(magtape, O_RDONLY);
+       else
+#endif
+               mt = OPEN(magtape, O_RDONLY, 0);
+
+       if (mt == -1) {
+               fprintf(stderr, "Cannot open %s\n", magtape);
+               volno = -1;
+               haderror = 1;
+               goto again;
+       }
+gethdr:
+       setmagtapein();
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+       readtape_func = readtape_set;
+#endif
+       volno = newvol;
+       setdumpnum();
+       FLUSHTAPEBUF();
+       findtapeblksize();
+       if (gethead(&tmpbuf) == FAIL) {
+               Dprintf(stdout, "header read failed at %ld blocks\n", (long)blksread);
+               fprintf(stderr, "tape is not dump tape\n");
+               volno = 0;
+               haderror = 1;
+               blksread = saved_blksread;
+               tpblksread = saved_tpblksread;
+               goto again;
+       }
+       if (tmpbuf.c_volume != volno) {
+               fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
+               volno = 0;
+               haderror = 1;
+               blksread = saved_blksread;
+               tpblksread = saved_tpblksread;
+               goto again;
+       }
+       if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
+               fprintf(stderr, "Wrong dump date\n\tgot: %s",
+#ifdef sunos
+                       ctime(&tmpbuf.c_date));
+#else
+                       ctime4(&tmpbuf.c_date));
+#endif
+               fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
+               volno = 0;
+               haderror = 1;
+               blksread = saved_blksread;
+               tpblksread = saved_tpblksread;
+               goto again;
+       }
+       tapesread |= 1 << volno;
+       /*
+        * If continuing from the previous volume, skip over any
+        * blocks read already at the end of the previous volume.
+        *
+        * If coming to this volume at random, skip to the beginning
+        * of the next record.
+        */
+       if (zflag) {
+               fprintf(stderr, "Dump tape is compressed.\n");
+#if !defined(HAVE_ZLIB) && !defined(HAVE_BZLIB) && !defined(HAVE_LZO)
+               errx(1,"This restore version doesn't support decompression");
+#endif /* !HAVE_ZLIB && !HAVE_BZLIB */
+       }
+       Dprintf(stdout, "read %ld recs, tape starts with %ld\n",
+               tpblksread - 1, (long)tmpbuf.c_firstrec);
+       if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
+               if (!wantnext) {
+                       tpblksread = tmpbuf.c_firstrec + 1;
+                       for (i = tmpbuf.c_count; i > 0; i--)
+                               readtape(buf);
+               } else if (tmpbuf.c_firstrec > 0 &&
+                          tmpbuf.c_firstrec < tpblksread - 1) {
+                       /*
+                        * -1 since we've read the volume header
+                        */
+                       i = tpblksread - tmpbuf.c_firstrec - 1;
+                       Dprintf(stderr, "Skipping %ld duplicate record%s.\n",
+                               (long)i, i > 1 ? "s" : "");
+                       while (--i >= 0)
+                               readtape(buf);
+               }
+       }
+       if (curfile.action == USING) {
+               if (volno == 1)
+                       panic("active file into volume 1\n");
+               return;
+       }
+       /*
+        * Skip up to the beginning of the next record
+        */
+       if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
+               for (i = tmpbuf.c_count; i > 0; i--)
+                       readtape(buf);
+       (void) gethead(&spcl);
+       findinode(&spcl);
+       if (gettingfile) {
+               gettingfile = 0;
+               siglongjmp(restart, 1);
+       }
+}
+
+/*
+ * Handle unexpected EOF.
+ */
+static void
+terminateinput(void)
+{
+
+       if (gettingfile && curfile.action == USING) {
+               printf("Warning: %s %s\n",
+                   "End-of-input encountered while extracting", curfile.name);
+       }
+       curfile.name = "<name unknown>";
+       curfile.action = UNKNOWN;
+       curfile.dip = NULL;
+       curfile.ino = maxino;
+       if (gettingfile) {
+               gettingfile = 0;
+               siglongjmp(restart, 1);
+       }
+}
+
+/*
+ * handle multiple dumps per tape by skipping forward to the
+ * appropriate one.
+ */
+static void
+setdumpnum(void)
+{
+       struct mtop tcom;
+
+       if (dumpnum == 1 || volno != 1)
+               return;
+       if (pipein)
+               errx(1, "Cannot have multiple dumps on pipe input");
+       tcom.mt_op = MTFSF;
+       tcom.mt_count = dumpnum - 1;
+#ifdef RRESTORE
+       if (host) {
+               if (rmtioctl(MTFSF, dumpnum - 1) < 0) {
+                       fprintf(stderr, "rmtioctl MTFSF: %s\n", strerror(errno));
+            exit(1);
+               }
+       } else
+#endif
+               if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) {
+                       fprintf(stderr, "rmtioctl MTFSF: %s\n", strerror(errno));
+                       exit(1);
+                       /* warn("ioctl MTFSF"); */
+               }
+}
+
+void
+printdumpinfo(void)
+{
+#ifdef sunos
+       Vprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
+       Vprintf(stdout, "Dumped from: %s",
+           (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
+       if (spcl.c_host[0] == '\0')
+               return;
+       Vprintf(stdout, "Level %d dump of %s on %s:%s\n",
+               spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
+       Vprintf(stdout, "Label: %s\n", spcl.c_label);
+#else
+       fprintf(stdout, "Dump   date: %s", ctime4(&spcl.c_date));
+       fprintf(stdout, "Dumped from: %s",
+           (spcl.c_ddate == 0) ? "the epoch\n" : ctime4(&spcl.c_ddate));
+       if (spcl.c_host[0] == '\0')
+               return;
+       fprintf(stdout, "Level %d dump of %s on %s:%s\n",
+               spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
+       fprintf(stdout, "Label: %s\n", spcl.c_label);
+#endif
+}
+
+void 
+printvolinfo(void)
+{
+       int i;
+
+       if (volinfo[1] == ROOTINO) {
+               printf("Starting inode numbers by volume:\n");
+               for (i = 1; i < (int)TP_NINOS && volinfo[i] != 0; ++i)
+                       printf("\tVolume %d: %lu\n", i, (unsigned long)volinfo[i]);
+       }
+}
+
+
+int
+extractfile(struct entry *ep, int doremove)
+{
+       unsigned int flags;
+       mode_t mode;
+       struct timeval timep[2];
+       char *name = myname(ep);
+
+       /* If removal is requested (-r mode) do remove it unless
+        * we are extracting a metadata only inode */
+       if (spcl.c_flags & DR_METAONLY) {
+               Vprintf(stdout, "file %s is metadata only\n", name);
+       }
+       else {
+               if (doremove) {
+                       removeleaf(ep);
+                       ep->e_flags &= ~REMOVED;
+               }
+       }
+
+       curfile.name = name;
+       curfile.action = USING;
+#if defined(__linux__) || defined(sunos)
+       timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
+       timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
+       timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
+       timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
+#else  /* __linux__ || sunos */
+       timep[0].tv_sec = curfile.dip->di_atime;
+       timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
+       timep[1].tv_sec = curfile.dip->di_mtime;
+       timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
+#endif /* __linux__ */
+       mode = curfile.dip->di_mode;
+       flags = curfile.dip->di_flags;
+       switch (mode & IFMT) {
+
+       default:
+               fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
+               skipfile();
+               return (FAIL);
+
+       case IFSOCK:
+               Vprintf(stdout, "skipped socket %s\n", name);
+               skipfile();
+               return (GOOD);
+
+       case IFDIR:
+               if (mflag) {
+                       if (ep == NULL || ep->e_flags & EXTRACT)
+                               panic("unextracted directory %s\n", name);
+                       skipfile();
+                       return (GOOD);
+               }
+               Vprintf(stdout, "extract file %s\n", name);
+               return (genliteraldir(name, curfile.ino));
+
+       case IFLNK:
+       {
+#ifdef HAVE_LCHOWN
+               uid_t luid = curfile.dip->di_uid;
+               gid_t lgid = curfile.dip->di_gid;
+#endif
+               if (! (spcl.c_flags & DR_METAONLY)) {
+                       lnkbuf[0] = '\0';
+                       pathlen = 0;
+                       getfile(xtrlnkfile, xtrlnkskip);
+                       if (pathlen == 0) {
+                               Vprintf(stdout,
+                                   "%s: zero length symbolic link (ignored)\n", name);
+                               return (GOOD);
+                       }
+                       if (linkit(lnkbuf, name, SYMLINK) == FAIL)
+                               return (FAIL);
+               }
+               else
+                       skipfile();
+
+#ifdef HAVE_LCHOWN
+               (void) lchown(name, luid, lgid);
+#endif
+               return (GOOD);
+       }
+
+       case IFIFO:
+               Vprintf(stdout, "extract fifo %s\n", name);
+               if (Nflag) {
+                       skipfile();
+                       return (GOOD);
+               }
+               if (! (spcl.c_flags & DR_METAONLY)) {
+                       if (uflag && !Nflag)
+                               (void)unlink(name);
+                       if (mkfifo(name, mode) < 0) {
+                               warn("%s: cannot create fifo", name);
+                               skipfile();
+                               return (FAIL);
+                       }
+               }
+               (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
+               (void) chmod(name, mode);
+               if (flags)
+#ifdef  __linux__
+                       (void) fsetflags(name, flags);
+#else
+#ifdef sunos
+                       {
+                       warn("%s: cannot call chflags", name);
+                       /* (void) chflags(name, flags); */
+                       }
+#else
+                       (void) chflags(name, flags);
+#endif
+#endif
+               skipfile();
+               utimes(name, timep);
+               return (GOOD);
+
+       case IFCHR:
+       case IFBLK:
+               Vprintf(stdout, "extract special file %s\n", name);
+               if (Nflag) {
+                       skipfile();
+                       return (GOOD);
+               }
+               if (! (spcl.c_flags & DR_METAONLY)) {
+                       if (uflag)
+                               (void)unlink(name);
+                       if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
+                               warn("%s: cannot create special file", name);
+                               skipfile();
+                               return (FAIL);
+                       }
+               }
+               (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
+               (void) chmod(name, mode);
+               if (flags)
+#ifdef __linux__
+                       {
+                       warn("%s: fsetflags called on a special file", name);
+                       (void) fsetflags(name, flags);
+                       }
+#else
+#ifdef sunos
+                       {
+                       warn("%s: cannot call chflags on a special file", name);
+                       /* (void) chflags(name, flags); */
+                       }
+#else
+                       {
+                       warn("%s: chflags called on a special file", name);
+                       (void) chflags(name, flags);
+                       }
+#endif
+#endif
+               skipfile();
+               utimes(name, timep);
+               return (GOOD);
+
+       case IFREG:
+       {
+               uid_t luid = curfile.dip->di_uid;
+               gid_t lgid = curfile.dip->di_gid;
+
+               Vprintf(stdout, "extract file %s\n", name);
+               if (Nflag) {
+                       skipfile();
+                       return (GOOD);
+               }
+               if (! (spcl.c_flags & DR_METAONLY)) {
+                       if (uflag)
+                               (void)unlink(name);
+                       if ((ofile = OPEN(name, O_WRONLY | O_CREAT | O_TRUNC,
+                           0666)) < 0) {
+                               warn("%s: cannot create file", name);
+                               skipfile();
+                               return (FAIL);
+                       }
+                       getfile(xtrfile, xtrskip);
+                       (void) close(ofile);
+               }
+               else
+                       skipfile();
+               (void) chown(name, luid, lgid);
+               (void) chmod(name, mode);
+               if (flags)
+#ifdef __linux__
+                       (void) fsetflags(name, flags);
+#else
+#ifdef sunos
+                       {
+                       warn("%s: cannot call chflags", name);
+                       /* (void) chflags(name, flags); */
+                       }
+#else
+                       (void) chflags(name, flags);
+#endif
+#endif
+               utimes(name, timep);
+               return (GOOD);
+       }
+       }
+       /* NOTREACHED */
+}
+
+#ifdef DUMP_MACOSX
+int
+extractfinderinfoufs(char *name)
+{
+       int err;
+       char                    oFileRsrc[MAXPATHLEN];
+       int flags;
+       mode_t mode;
+       struct timeval timep[2];
+       u_int32_t       uid;
+       u_int32_t       gid;
+       char    path[MAXPATHLEN], fname[MAXPATHLEN];
+       int toto;
+
+       curfile.name = name;
+       curfile.action = USING;
+       timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
+       timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
+       timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
+       timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
+       mode = curfile.dip->di_mode;
+       flags = curfile.dip->di_flags;
+        uid = curfile.dip->di_uid;
+        gid =  curfile.dip->di_gid;
+
+       switch (mode & IFMT) {
+
+       default:
+               fprintf(stderr, "%s: (extr. finfoufs) unknown file mode 0%o\n", name, mode);
+               skipfile();
+               return (FAIL);
+
+       case IFDIR:
+               fprintf(stderr, "%s: (extr. finfoufs[IFDIR]) unknown file mode 0%o\n", name, mode);
+               skipfile();
+               return (FAIL);
+
+       case IFLNK:
+               skipfile();
+               return (GOOD);
+
+       case IFREG:
+               Vprintf(stdout, "extract finderinfo file %s\n", name);
+               if (Nflag) {
+                       skipfile();
+                       return (GOOD);
+               }
+               getfile(xtrfilefinderinfo, xtrskip);
+
+               GetPathFile(name, path, fname);
+               strcpy(oFileRsrc, path);
+               strcat(oFileRsrc, "._");
+               strcat(oFileRsrc, fname);
+
+               if ((err = CreateAppleDoubleFileRes(oFileRsrc, &gFndrInfo.fndrinfo,
+                               mode, flags, timep, uid, gid)) != 0) {
+                       fprintf(stderr, "%s: cannot create finderinfo: %s\n",
+                       name, strerror(errno));
+                       skipfile();
+                       return (FAIL);
+               }
+               return (GOOD);
+       }
+       /* NOTREACHED */
+}
+
+
+int
+extractresourceufs(char *name)
+{
+       char                    oFileRsrc[MAXPATHLEN];
+       int flags;
+       mode_t mode;
+       struct timeval timep[2];
+       char    path[MAXPATHLEN], fname[MAXPATHLEN];
+       ASDHeaderPtr    hp;
+       ASDEntryPtr     ep;
+       u_long  loff;
+        u_int32_t      uid;
+       u_int32_t       gid;
+       u_int64_t       di_size;
+       char            *p;
+       char            buf[1024];
+
+       curfile.name = name;
+       curfile.action = USING;
+       timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
+       timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
+       timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
+       timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
+       mode = curfile.dip->di_mode;
+       flags = curfile.dip->di_flags;
+       uid = curfile.dip->di_uid;
+       gid =  curfile.dip->di_gid;
+       di_size = curfile.dip->di_size;
+
+       switch (mode & IFMT) {
+
+       default:
+               fprintf(stderr, "%s: (extr. resufs) unknown file mode 0%o\n", name, mode);
+               skipfile();
+               return (FAIL);
+
+       case IFDIR:
+               fprintf(stderr, "%s: (extr. resufs [IFDIR]) unknown file mode 0%o\n", name, mode);
+               skipfile();
+               return (FAIL);
+
+       case IFLNK:
+               skipfile();
+               return (GOOD);
+
+       case IFREG:
+               Vprintf(stdout, "extract resource file %s\n", name);
+               if (Nflag) {
+                       skipfile();
+                       return (GOOD);
+               }
+
+               GetPathFile(name, path, fname);
+               strcpy(oFileRsrc, path);
+               strcat(oFileRsrc, "._");
+               strcat(oFileRsrc, fname);
+
+               if ((ofile = open(oFileRsrc, O_RDONLY, 0)) < 0) {
+                       fprintf(stderr, "%s: cannot read finderinfo: %s\n",
+                           name, strerror(errno));
+                       skipfile();
+                       return (FAIL);
+               }
+               read(ofile, buf, 70);
+               (void) close(ofile);
+               p = buf;
+               hp = (ASDHeaderPtr)p;
+               /* the header */
+               hp->entries++;
+               p += sizeof(ASDHeader) - CORRECT;
+               ep = (ASDEntryPtr)p;
+               /* the finderinfo entry */
+               ep->offset += sizeof(ASDEntry);
+               loff = ep->offset;
+
+               p += sizeof(ASDEntry);
+               /* the finderinfo data */
+               bcopy(p, p + sizeof(ASDEntry), INFOLEN);
+               ep = (ASDEntryPtr)p;
+               /* the new resourcefork entry */
+               ep->entryID = EntryRSRCFork;
+               ep->offset = loff + INFOLEN;
+               ep->len = di_size;
+               /* write the new appledouble entries to the file */
+               if ((ofile = open(oFileRsrc, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
+                       fprintf(stderr, "%s: cannot create resource file: %s\n",
+                           name, strerror(errno));
+                       skipfile();
+                       return (FAIL);
+               }
+               write(ofile, buf, 70 + sizeof(ASDEntry));
+               /* and add the resource data from tape */
+               getfile(xtrfile, xtrskip);
+
+               (void) fchown(ofile, uid, gid);
+               (void) fchmod(ofile, mode);
+               (void) close(ofile);
+               (void) fsetflags(oFileRsrc, flags);
+               utimes(oFileRsrc, timep);
+               return (GOOD);
+       }
+       /* NOTREACHED */
+}
+#endif /* DUMP_MACOSX */
+
+/*
+ * skip over bit maps on the tape
+ */
+void
+skipmaps(void)
+{
+
+       while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
+               skipfile();
+}
+
+/*
+ * skip over a file on the tape
+ */
+void
+skipfile(void)
+{
+
+       curfile.action = SKIP;
+       getfile(xtrnull, xtrnull);
+}
+
+/*
+ * Extract a file from the tape.
+ * When an allocated block is found it is passed to the fill function;
+ * when an unallocated block (hole) is found, a zeroed buffer is passed
+ * to the skip function.
+ */
+void
+getfile(void (*fill) __P((char *, size_t)), void (*skip) __P((char *, size_t)))
+{
+       int i;
+       volatile int curblk = 0;
+       volatile quad_t size = spcl.c_dinode.di_size;
+       volatile int last_write_was_hole = 0;
+       quad_t origsize = size;
+       static char clearedbuf[MAXBSIZE];
+       char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
+       char junk[TP_BSIZE];
+
+       if (spcl.c_type == TS_END)
+               panic("ran off end of tape\n");
+       if (spcl.c_magic != NFS_MAGIC)
+               panic("not at beginning of a file\n");
+       if (!gettingfile && setjmp(restart) != 0)
+               return;
+       gettingfile++;
+loop:
+       for (i = 0; i < spcl.c_count; i++) {
+               if (readmapflag || spcl.c_addr[i]) {
+                       readtape(&buf[curblk++][0]);
+                       if (curblk == fssize / TP_BSIZE) {
+                               (*fill)((char *)buf, (size_t)(size > TP_BSIZE ?
+                                    fssize : (curblk - 1) * TP_BSIZE + size));
+                               curblk = 0;
+                               last_write_was_hole = 0;
+                       }
+               } else {
+                       if (curblk > 0) {
+                               (*fill)((char *)buf, (size_t)(size > TP_BSIZE ?
+                                    curblk * TP_BSIZE :
+                                    (curblk - 1) * TP_BSIZE + size));
+                               curblk = 0;
+                       }
+                       (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
+                               TP_BSIZE : size));
+                       last_write_was_hole = 1;
+               }
+               if ((size -= TP_BSIZE) <= 0) {
+                       for (i++; i < spcl.c_count; i++)
+                               if (readmapflag || spcl.c_addr[i])
+                                       readtape(junk);
+                       break;
+               }
+       }
+       if (gethead(&spcl) == GOOD && size > 0) {
+               if (spcl.c_type == TS_ADDR)
+                       goto loop;
+               Dprintf(stdout,
+                       "Missing address (header) block for %s at %ld blocks\n",
+                       curfile.name, (long)blksread);
+       }
+       if (curblk > 0) {
+               (*fill)((char *)buf, (size_t)((curblk * TP_BSIZE) + size));
+               last_write_was_hole = 0;
+       }
+       if (size > 0) {
+               fprintf(stderr, "Missing blocks at the end of %s, assuming hole\n", curfile.name);
+               while (size > 0) {
+                       size_t skp = size > TP_BSIZE ? TP_BSIZE : size;
+                       (*skip)(clearedbuf, skp);
+                       size -= skp;
+               }
+               last_write_was_hole = 1;
+       }
+       if (last_write_was_hole) {
+               FTRUNCATE(ofile, origsize);
+       }
+       if (!readingmaps) 
+               findinode(&spcl);
+       gettingfile = 0;
+}
+
+/*
+ * Write out the next block of a file.
+ */
+static void
+xtrfile(char *buf, size_t size)
+{
+
+       if (Nflag)
+               return;
+       if (write(ofile, buf, (int) size) == -1)
+               err(1, "write error extracting inode %lu, name %s\nwrite",
+                       (unsigned long)curfile.ino, curfile.name);
+}
+
+#ifdef DUMP_MACOSX
+static void
+xtrfilefinderinfo(char *buf, size_t size)
+{
+       if (Nflag)
+               return;
+       bcopy(buf, &gFndrInfo, size);
+}
+#endif /* DUMP_MACOSX */
+
+/*
+ * Skip over a hole in a file.
+ */
+/* ARGSUSED */
+static void
+xtrskip(UNUSED(char *buf), size_t size)
+{
+
+       if (LSEEK(ofile, (OFF_T)size, SEEK_CUR) == -1)
+               err(1, "seek error extracting inode %lu, name %s\nlseek",
+                       (unsigned long)curfile.ino, curfile.name);
+}
+
+/*
+ * Collect the next block of a symbolic link.
+ */
+static void
+xtrlnkfile(char *buf, size_t size)
+{
+
+       pathlen += size;
+       if (pathlen > MAXPATHLEN)
+               errx(1, "symbolic link name: %s->%s%s; too long %d",
+                   curfile.name, lnkbuf, buf, pathlen);
+       (void) strcat(lnkbuf, buf);
+}
+
+/*
+ * Skip over a hole in a symbolic link (should never happen).
+ */
+/* ARGSUSED */
+static void
+xtrlnkskip(UNUSED(char *buf), UNUSED(size_t size))
+{
+
+       errx(1, "unallocated block in symbolic link %s", curfile.name);
+}
+
+/*
+ * Collect the next block of a bit map.
+ */
+static void
+xtrmap(char *buf, size_t size)
+{
+
+       memmove(map, buf, size);
+       map += size;
+}
+
+/*
+ * Skip over a hole in a bit map (should never happen).
+ */
+/* ARGSUSED */
+static void
+xtrmapskip(UNUSED(char *buf), size_t size)
+{
+
+       panic("hole in map\n");
+       map += size;
+}
+
+/*
+ * Noop, when an extraction function is not needed.
+ */
+/* ARGSUSED */
+void
+xtrnull(UNUSED(char *buf), UNUSED(size_t size))
+{
+
+       return;
+}
+
+#if COMPARE_ONTHEFLY
+/*
+ * Compare the next block of a file.
+ */
+static void
+xtrcmpfile(char *buf, size_t size)
+{
+       static char cmpbuf[MAXBSIZE];
+
+       if (cmperror)
+               return;
+       
+       if (read(ifile, cmpbuf, size) != (ssize_t)size) {
+               fprintf(stderr, "%s: size has changed.\n", 
+                       curfile.name);
+               cmperror = 1;
+               return;
+       }
+       
+       if (memcmp(buf, cmpbuf, size) != 0) {
+               fprintf(stderr, "%s: tape and disk copies are different\n",
+                       curfile.name);
+               cmperror = 1;
+               return;
+       }
+}
+
+/*
+ * Skip over a hole in a file.
+ */
+static void
+xtrcmpskip(UNUSED(char *buf), size_t size)
+{
+       static char cmpbuf[MAXBSIZE];
+       int i;
+
+       if (cmperror)
+               return;
+       
+       if (read(ifile, cmpbuf, size) != (ssize_t)size) {
+               fprintf(stderr, "%s: size has changed.\n", 
+                       curfile.name);
+               cmperror = 1;
+               return;
+       }
+
+       for (i = 0; i < (int)size; ++i)
+               if (cmpbuf[i] != '\0') {
+                       fprintf(stderr, "%s: tape and disk copies are different\n",
+                               curfile.name);
+                       cmperror = 1;
+                       return;
+               }
+}
+#endif /* COMPARE_ONTHEFLY */
+
+#if !COMPARE_ONTHEFLY
+static int
+do_cmpfiles(int fd_tape, int fd_disk, long size)
+{
+       static char buf_tape[BUFSIZ];
+       static char buf_disk[BUFSIZ];
+       ssize_t n_tape;
+       ssize_t n_disk;
+
+       while (size > 0) {
+               if ((n_tape = read(fd_tape, buf_tape, sizeof(buf_tape))) < 1) {
+                       close(fd_tape), close(fd_disk);
+                       panic("do_cmpfiles: unexpected EOF[1]");
+               }
+               if ((n_disk = read(fd_disk, buf_disk, sizeof(buf_tape))) < 1) {
+                       close(fd_tape), close(fd_disk);
+                       panic("do_cmpfiles: unexpected EOF[2]");
+               }
+               if (n_tape != n_disk) {
+                       close(fd_tape), close(fd_disk);
+                       panic("do_cmpfiles: sizes different!");
+               }
+               if (memcmp(buf_tape, buf_disk, (size_t)n_tape) != 0) return (1);
+               size -= n_tape;
+       }
+       return (0);
+}
+
+/* for debugging compare problems */
+#undef COMPARE_FAIL_KEEP_FILE
+
+static
+#ifdef COMPARE_FAIL_KEEP_FILE
+/* return true if tapefile should be unlinked after compare */
+int
+#else
+void
+#endif
+cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk)
+{
+       struct STAT sbuf_tape;
+       int fd_tape, fd_disk;
+
+       if (STAT(tapefile, &sbuf_tape) != 0) {
+               panic("Can't lstat tmp file %s: %s\n", tapefile,
+                     strerror(errno));
+               do_compare_error;
+       }
+
+       if (sbuf_disk->st_size != sbuf_tape.st_size) {
+               fprintf(stderr,
+                       "%s: size changed from %ld to %ld.\n",
+                       diskfile, (long)sbuf_tape.st_size, (long)sbuf_disk->st_size);
+               do_compare_error;
+#ifdef COMPARE_FAIL_KEEP_FILE
+               return (0);
+#else
+               return;
+#endif
+       }
+
+       if ((fd_tape = OPEN(tapefile, O_RDONLY)) < 0) {
+               panic("Can't open %s: %s\n", tapefile, strerror(errno));
+               do_compare_error;
+       }
+       if ((fd_disk = OPEN(diskfile, O_RDONLY)) < 0) {
+               close(fd_tape);
+               panic("Can't open %s: %s\n", diskfile, strerror(errno));
+               do_compare_error;
+       }
+
+       if (do_cmpfiles(fd_tape, fd_disk, sbuf_tape.st_size)) {
+               fprintf(stderr, "%s: tape and disk copies are different\n",
+                       diskfile);
+               close(fd_tape);
+               close(fd_disk);
+               do_compare_error;
+#ifdef COMPARE_FAIL_KEEP_FILE
+               /* rename the file to live in /tmp */
+               /* rename `tapefile' to /tmp/<basename of diskfile> */
+               {
+                       char *p = strrchr(diskfile, '/');
+                       char newname[MAXPATHLEN];
+                       if (!p) {
+                               panic("can't find / in %s\n", diskfile);
+                       }
+                       snprintf(newname, sizeof(newname), "%s/debug/%s", tmpdir, p + 1);
+                       if (rename(tapefile, newname)) {
+                               panic("rename from %s to %s failed: %s\n",
+                                     tapefile, newname,
+                                     strerror(errno));
+                       } else {
+                               fprintf(stderr, "*** %s saved to %s\n",
+                                       tapefile, newname);
+                       }
+               }
+               
+               /* don't unlink the file (it's not there anymore */
+               /* anyway) */
+               return (0);
+#else
+               return;
+#endif
+       }
+       close(fd_tape);
+       close(fd_disk);
+#ifdef COMPARE_FAIL_KEEP_FILE
+       return (1);
+#endif
+}
+#endif /* !COMPARE_ONTHEFLY */
+
+#if !COMPARE_ONTHEFLY
+static char tmpfilename[MAXPATHLEN];
+#endif
+
+void
+comparefile(char *name)
+{
+       unsigned int mode;
+       struct STAT sb;
+       int r;
+#if !COMPARE_ONTHEFLY
+       static char *tmpfile = NULL;
+       struct STAT stemp;
+#endif
+
+       curfile.name = name;
+       curfile.action = USING;
+       mode = curfile.dip->di_mode;
+
+       if ((mode & IFMT) == IFSOCK) {
+               Vprintf(stdout, "skipped socket %s\n", name);
+               skipfile();
+               return;
+       }
+
+       if ((r = LSTAT(name, &sb)) != 0) {
+               warn("%s: does not exist (%d)", name, r);
+               do_compare_error;
+               skipfile();
+               return;
+       }
+
+       Vprintf(stdout, "comparing %s (size: %ld, mode: 0%o)\n", name,
+               (long)sb.st_size, mode);
+
+       if (sb.st_mode != mode) {
+               fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n",
+                       name, mode & 07777, sb.st_mode & 07777);
+               do_compare_error;
+       }
+       if (spcl.c_flags & DR_METAONLY) {
+               skipfile();
+               return;
+       }
+       switch (mode & IFMT) {
+       default:
+               skipfile();
+               return;
+
+       case IFSOCK:
+               skipfile();
+               return;
+
+       case IFDIR:
+               skipfile();
+               return;
+
+       case IFLNK: {
+               char lbuf[MAXPATHLEN + 1];
+               int lsize;
+
+               if (!(sb.st_mode & S_IFLNK)) {
+                       fprintf(stderr, "%s: is no longer a symbolic link\n",
+                               name);
+                       do_compare_error;
+                       return;
+               }
+               lnkbuf[0] = '\0';
+               pathlen = 0;
+               getfile(xtrlnkfile, xtrlnkskip);
+               if (pathlen == 0) {
+                       fprintf(stderr,
+                               "%s: zero length symbolic link (ignored)\n",
+                               name);
+                       do_compare_error;
+                       return;
+               }
+               if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) {
+                       panic("readlink of %s failed: %s", name,
+                             strerror(errno));
+                       do_compare_error;
+               }
+               lbuf[lsize] = 0;
+               if (strcmp(lbuf, lnkbuf) != 0) {
+                       fprintf(stderr,
+                               "%s: symbolic link changed from %s to %s.\n",
+                               name, lnkbuf, lbuf);
+                       do_compare_error;
+                       return;
+               }
+               return;
+       }
+
+       case IFCHR:
+       case IFBLK:
+               if (!(sb.st_mode & (S_IFCHR|S_IFBLK))) {
+                       fprintf(stderr, "%s: no longer a special file\n",
+                               name);
+                       do_compare_error;
+                       skipfile();
+                       return;
+               }
+
+               if (sb.st_rdev != (dev_t)curfile.dip->di_rdev) {
+                       fprintf(stderr,
+                               "%s: device changed from %d,%d to %d,%d.\n",
+                               name,
+                               major(curfile.dip->di_rdev),
+                               minor(curfile.dip->di_rdev),
+                               major(sb.st_rdev),
+                               minor(sb.st_rdev));
+                       do_compare_error;
+               }
+               skipfile();
+               return;
+
+       case IFREG:
+#if COMPARE_ONTHEFLY
+               if ((ifile = OPEN(name, O_RDONLY)) < 0) {
+                       panic("Can't open %s: %s\n", name, strerror(errno));
+                       skipfile();
+                       do_compare_error;
+               }
+               else {
+                       cmperror = 0;
+                       getfile(xtrcmpfile, xtrcmpskip);
+                       if (!cmperror) {
+                               char c;
+                               if (read(ifile, &c, 1) != 0) {
+                                       fprintf(stderr, "%s: size has changed.\n", 
+                                               name);
+                                       cmperror = 1;
+                               }
+                       }
+                       if (cmperror)
+                               do_compare_error;
+                       close(ifile);
+               }
+#else
+               if (tmpfile == NULL) {
+                       /* argument to mktemp() must not be in RO space: */
+                       snprintf(tmpfilename, sizeof(tmpfilename), "%s/restoreCXXXXXX", tmpdir);
+                       tmpfile = mktemp(&tmpfilename[0]);
+               }
+               if ((STAT(tmpfile, &stemp) == 0) && (unlink(tmpfile) != 0)) {
+                       panic("cannot delete tmp file %s: %s\n",
+                             tmpfile, strerror(errno));
+               }
+               if ((ofile = OPEN(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
+                       panic("cannot create file temp file %s: %s\n",
+                             name, strerror(errno));
+               }
+               getfile(xtrfile, xtrskip);
+               (void) close(ofile);
+#ifdef COMPARE_FAIL_KEEP_FILE
+               if (cmpfiles(tmpfile, name, &sb))
+                       unlink(tmpfile);
+#else
+               cmpfiles(tmpfile, name, &sb);
+               unlink(tmpfile);
+#endif
+#endif /* COMPARE_ONTHEFLY */
+               return;
+       }
+       /* NOTREACHED */
+}
+
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+static void (*readtape_func)(char *) = readtape_set;
+
+/*
+ * Read TP_BSIZE blocks from the input.
+ * Handle read errors, and end of media.
+ * Decompress compressed blocks.
+ */
+static void
+readtape(char *buf)
+{
+       (*readtape_func)(buf);  /* call the actual processing routine */
+}
+
+/*
+ * Set function pointer for readtape() routine. zflag and magtapein must
+ * be correctly set before the first call to readtape().
+ */
+static void
+readtape_set(char *buf)
+{
+       if (!zflag) 
+               readtape_func = readtape_uncompr;
+       else {
+               newcomprbuf(ntrec);
+               if (magtapein)
+                       readtape_func = readtape_comprtape;
+               else
+                       readtape_func = readtape_comprfile;
+       }
+       readtape(buf);
+}
+
+#endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
+
+/*
+ * This is the original readtape(), it's used for reading uncompressed input.
+ * Read TP_BSIZE blocks from the input.
+ * Handle read errors, and end of media.
+ */
+static void
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+readtape_uncompr(char *buf)
+#else
+readtape(char *buf)
+#endif
+{
+       ssize_t rd, newvol, i;
+       int cnt, seek_failed;
+
+       if (blkcnt < numtrec) {
+               memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
+               blksread++;
+               tpblksread++;
+               return;
+       }
+       tbufptr = tapebuf;
+       for (i = 0; i < ntrec; i++)
+               ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
+       if (numtrec == 0)
+               numtrec = ntrec;
+       cnt = ntrec * TP_BSIZE;
+       rd = 0;
+#ifdef USE_QFA
+       if (createtapeposflag)
+               (void)GetTapePos(&curtapepos);
+#endif
+getmore:
+#ifdef RRESTORE
+       if (!Afile && host)
+               i = rmtread(&tapebuf[rd], cnt);
+       else
+#endif
+               i = read(mt, &tapebuf[rd], cnt);
+
+       /*
+        * Check for mid-tape short read error.
+        * If found, skip rest of buffer and start with the next.
+        */
+       if (!pipein && numtrec < ntrec && i > 0) {
+               Dprintf(stdout, "mid-media short read error.\n");
+               numtrec = ntrec;
+       }
+       /*
+        * Handle partial block read.
+        */
+       if (pipein && i == 0 && rd > 0)
+               i = rd;
+       else if (i > 0 && i != ntrec * TP_BSIZE) {
+               if (pipein) {
+                       rd += i;
+                       cnt -= i;
+                       if (cnt > 0)
+                               goto getmore;
+                       i = rd;
+               } else {
+                       /*
+                        * Short read. Process the blocks read.
+                        */
+                       if (i % TP_BSIZE != 0)
+                               Vprintf(stdout,
+                                   "partial block read: %ld should be %ld\n",
+                                   (long)i, ntrec * TP_BSIZE);
+                       numtrec = i / TP_BSIZE;
+               }
+       }
+       /*
+        * Handle read error.
+        */
+       if (i < 0) {
+               fprintf(stderr, "Tape read error while ");
+               switch (curfile.action) {
+               default:
+                       fprintf(stderr, "trying to set up tape\n");
+                       break;
+               case UNKNOWN:
+                       fprintf(stderr, "trying to resynchronize\n");
+                       break;
+               case USING:
+                       fprintf(stderr, "restoring %s\n", curfile.name);
+                       break;
+               case SKIP:
+                       fprintf(stderr, "skipping over inode %lu\n",
+                               (unsigned long)curfile.ino);
+                       break;
+               }
+               if (!yflag && !reply("continue"))
+                       exit(1);
+               i = ntrec * TP_BSIZE;
+               memset(tapebuf, 0, (size_t)i);
+#ifdef RRESTORE
+               if (!Afile && host)
+                       seek_failed = (rmtseek(i, 1) < 0);
+               else
+#endif
+                       seek_failed = (LSEEK(mt, i, SEEK_CUR) == (OFF_T)-1);
+
+               if (seek_failed) {
+                       warn("continuation failed");
+                       if (!yflag && !reply("assume end-of-tape and continue"))
+                               exit(1);
+                       i = 0;
+               }
+       }
+       /*
+        * Handle end of tape.
+        */
+       if (i == 0) {
+               Vprintf(stdout, "End-of-tape encountered\n");
+               if (!pipein) {
+                       newvol = volno + 1;
+                       volno = 0;
+                       numtrec = 0;
+                       getvol(newvol);
+                       readtape(buf);
+                       return;
+               }
+               if (rd % TP_BSIZE != 0)
+                       panic("partial block read: %d should be %d\n",
+                               rd, ntrec * TP_BSIZE);
+               terminateinput();
+               memmove(&tapebuf[rd], &endoftapemark, TP_BSIZE);
+       }
+       blkcnt = 0;
+       memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
+       blksread++;
+       tpblksread++;
+}
+
+#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
+
+/*
+ * Read a compressed format block from a file or pipe and uncompress it.
+ * Attempt to handle read errors, and end of file. 
+ */
+static void
+readtape_comprfile(char *buf)
+{
+       long rl, size, i, ret;
+       int newvol; 
+       struct tapebuf *tpb;
+
+       if (blkcnt < numtrec) {
+               memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
+               blksread++;
+               tpblksread++;
+               return;
+       }
+       /* need to read the next block */
+       tbufptr = tapebuf;
+       for (i = 0; i < ntrec; i++)
+               ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
+       numtrec = ntrec;
+       tpb = (struct tapebuf *) tapebuf;
+
+       /* read the block prefix */
+       ret = read_a_block(mt, tapebuf, PREFIXSIZE, &rl);
+       converttapebuf(tpb);
+
+       if (Vflag && (ret == 0 || rl < (int)PREFIXSIZE  ||  tpb->length == 0))
+               ret = 0;
+       if (ret <= 0)
+               goto readerr;
+
+       /* read the data */
+       size = tpb->length;
+       if (size > bufsize)  {
+               /* something's wrong */
+               Vprintf(stdout, "Prefix size error, max size %d, got %ld\n",
+                       bufsize, size);
+               size = bufsize;
+               tpb->length = bufsize;
+       }
+       ret = read_a_block(mt, tpb->buf, size, &rl);
+       if (ret <= 0)
+               goto readerr;
+
+       tbufptr = decompress_tapebuf(tpb, rl + PREFIXSIZE);
+       if (tbufptr == NULL) {
+               msg_read_error("File decompression error while");
+               if (!yflag && !reply("continue"))
+                       exit(1);
+               memset(tapebuf, 0, bufsize);
+               tbufptr = tapebuf;
+       }
+
+       blkcnt = 0;
+       memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
+       blksread++;
+       tpblksread++;
+       return;
+
+readerr:
+       /* Errors while reading from a file or pipe are catastrophic. Since
+        * there are no block boundaries, it's impossible to bypass the
+        * block in error and find the start of the next block.
+        */
+       if (ret == 0) {
+               /* It's possible to have multiple input files using -M
+                * and -f file1,file2...
+                */
+               Vprintf(stdout, "End-of-File encountered\n");
+               if (!pipein) {
+                       newvol = volno + 1;
+                       volno = 0;
+                       numtrec = 0;
+                       getvol(newvol);
+                       readtape(buf);
+                       return;
+               }
+       }
+       msg_read_error("Read error while");
+       /* if (!yflag && !reply("continue")) */
+               exit(1);
+}
+
+/*
+ * Read compressed data from a tape and uncompress it.
+ * Handle read errors, and end of media.
+ * Since a tape consists of separate physical blocks, we try
+ * to recover from errors by repositioning the tape to the next
+ * block.
+ */
+static void
+readtape_comprtape(char *buf)
+{
+       long rl, size, i;
+       int ret, newvol;
+       struct tapebuf *tpb;
+       struct mtop tcom;
+
+       if (blkcnt < numtrec) {
+               memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
+               blksread++;
+               tpblksread++;
+               return;
+       }
+       /* need to read the next block */
+       tbufptr = tapebuf;
+       for (i = 0; i < ntrec; i++)
+               ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
+       numtrec = ntrec;
+       tpb = (struct tapebuf *) tapebuf;
+
+       /* read the block */
+       size = bufsize + PREFIXSIZE;
+       ret = read_a_block(mt, tapebuf, size, &rl);
+       if (ret <= 0)
+               goto readerr;
+
+       converttapebuf(tpb);
+       tbufptr = decompress_tapebuf(tpb, rl);
+       if (tbufptr == NULL) {
+               msg_read_error("Tape decompression error while");
+               if (!yflag && !reply("continue"))
+                       exit(1);
+               memset(tapebuf, 0, PREFIXSIZE + bufsize);
+               tbufptr = tapebuf;
+       }
+       goto moverecord;
+
+readerr:
+       /* Handle errors: EOT switches to the next volume, other errors
+        * attempt to position the tape to the next block.
+        */
+       if (ret == 0) {
+               Vprintf(stdout, "End-of-tape encountered\n");
+               newvol = volno + 1;
+               volno = 0;
+               numtrec = 0;
+               getvol(newvol);
+               readtape(buf);
+               return;
+       }
+
+       msg_read_error("Tape read error while");
+       if (!yflag && !reply("continue"))
+               exit(1);
+       memset(tapebuf, 0, PREFIXSIZE + bufsize);
+       tbufptr = tapebuf;
+
+#ifdef RRESTORE
+       if (host)
+               rl = rmtioctl(MTFSR, 1);
+       else
+#endif
+       {
+               tcom.mt_op = MTFSR;
+               tcom.mt_count = 1;
+               rl = ioctl(mt, MTIOCTOP, &tcom);
+       }
+
+       if (rl < 0) {
+               warn("continuation failed");
+               if (!yflag && !reply("assume end-of-tape and continue"))
+                       exit(1);
+               ret = 0;         /* end of tape */
+               goto readerr;
+       }
+
+moverecord:
+       blkcnt = 0;
+       memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
+       blksread++;
+       tpblksread++;
+}
+
+/*
+ *  Decompress a struct tapebuf into a buffer. readsize is the size read
+ *  from the tape/file and is used for error messages. Returns a pointer
+ *  to the location of the uncompressed buffer or NULL on errors.
+ *  Adjust numtrec and complain for a short block.
+ */
+static char *
+decompress_tapebuf(struct tapebuf *tpbin, int readsize)
+{
+       /* If zflag is on, all blocks have a struct tapebuf prefix */
+       /* zflag gets set in setup() from the dump header          */
+       int cresult, blocklen;        
+       unsigned long worklen;
+       char *output = NULL,*reason = NULL, *lengtherr = NULL;              
+       
+       /* build a length error message */
+       blocklen = tpbin->length;
+       if (readsize < blocklen + (int)PREFIXSIZE)
+               lengtherr = "short";
+       else
+               if (readsize > blocklen + (int)PREFIXSIZE)
+                       lengtherr = "long";
+
+       worklen = comprlen;
+       cresult = 1;
+       if (tpbin->compressed) {
+               /* uncompress whatever we read, if it fails, complain later */
+               if (tpbin->flags == COMPRESS_ZLIB) {
+#ifndef HAVE_ZLIB
+                       errx(1,"This restore version doesn't support zlib decompression");
+#else
+                       cresult = uncompress(comprbuf, &worklen, 
+                                            tpbin->buf, blocklen);
+                       output = comprbuf;
+                       switch (cresult) {
+                               case Z_OK:
+                                       break;
+                               case Z_MEM_ERROR:
+                                       reason = "not enough memory";
+                                       break;
+                               case Z_BUF_ERROR:
+                                       reason = "buffer too small";
+                                       break;
+                               case Z_DATA_ERROR:
+                                       reason = "data error";
+                                       break;
+                               default:
+                                       reason = "unknown";
+                       }
+                       if (cresult == Z_OK)
+                               cresult = 1;
+                       else
+                               cresult = 0;
+#endif /* HAVE_ZLIB */
+               }
+               if (tpbin->flags == COMPRESS_BZLIB) {
+#ifndef HAVE_BZLIB
+                       errx(1,"This restore version doesn't support bzlib decompression");
+#else
+                       unsigned int worklen2 = worklen;
+                       cresult = BZ2_bzBuffToBuffDecompress(
+                                       comprbuf, &worklen2, 
+                                       tpbin->buf, blocklen, 0, 0);
+                       worklen = worklen2;
+                       output = comprbuf;
+                       switch (cresult) {
+                               case BZ_OK:
+                                       break;
+                               case BZ_MEM_ERROR:
+                                       reason = "not enough memory";
+                                       break;
+                               case BZ_OUTBUFF_FULL:
+                                       reason = "buffer too small";
+                                       break;
+                               case BZ_DATA_ERROR:
+                               case BZ_DATA_ERROR_MAGIC:
+                               case BZ_UNEXPECTED_EOF:
+                                       reason = "data error";
+                                       break;
+                               default:
+                                       reason = "unknown";
+                       }
+                       if (cresult == BZ_OK)
+                               cresult = 1;
+                       else
+                               cresult = 0;
+#endif /* HAVE_BZLIB */
+               }
+               if (tpbin->flags == COMPRESS_LZO) {
+#ifndef HAVE_LZO
+                       errx(1,"This restore version doesn't support lzo decompression");
+#else
+                       lzo_uint worklen2 = worklen;
+                       cresult = lzo1x_decompress(tpbin->buf, blocklen,
+                                                   comprbuf, &worklen2, NULL);
+                       worklen = worklen2;
+                       output = comprbuf;
+                       switch (cresult) {
+                               case LZO_E_OK:
+                                       break;
+                                case LZO_E_ERROR:
+                                case LZO_E_EOF_NOT_FOUND:
+                                       reason = "data error";
+                                       break;
+                               default:
+                                       reason = "unknown";
+                       }
+                       if (cresult == LZO_E_OK)
+                               cresult = 1;
+                       else
+                               cresult = 0;
+#endif /* HAVE_LZO */
+               }
+       }
+       else {
+               output = tpbin->buf;
+               worklen = blocklen;
+       }
+       if (cresult) {
+               numtrec = worklen / TP_BSIZE;
+               if (worklen % TP_BSIZE != 0)
+                       reason = "length mismatch";
+       }
+       if (reason) {
+               if (lengtherr)
+                       fprintf(stderr, "%s compressed block: %d expected: %u\n",
+                               lengtherr, readsize, tpbin->length + PREFIXSIZE);
+               fprintf(stderr, "decompression error, block %ld: %s\n",
+                       tpblksread+1, reason);
+               if (!cresult)
+                       output = NULL;
+       }
+       return output;
+}
+
+/*
+ * Print an error message for a read error.
+ * This was exteracted from the original readtape().
+ */
+static void
+msg_read_error(char *m)
+{
+       switch (curfile.action) {
+               default:
+                       fprintf(stderr, "%s trying to set up tape\n", m);
+                       break;
+               case UNKNOWN:
+                       fprintf(stderr, "%s trying to resynchronize\n", m);
+                       break;
+               case USING:
+                       fprintf(stderr, "%s restoring %s\n", m, curfile.name);
+                       break;
+               case SKIP:
+                       fprintf(stderr, "%s skipping over inode %lu\n", m,
+                               (unsigned long)curfile.ino);
+                       break;
+       }
+}
+#endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
+
+/*
+ * Read the first block and get the blocksize from it. Test
+ * for a compressed dump tape/file. setup() will make the final
+ * determination by checking the compressed flag if gethead()
+ * finds a valid header. The test here is necessary to offset the buffer
+ * by the size of the compressed prefix. zflag is set here so that
+ * readtape_set can set the correct function pointer for readtape().
+ * Note that the first block of each tape/file is not compressed
+ * and does not have a prefix.
+ */ 
+static void
+findtapeblksize(void)
+{
+       long i;
+       size_t len;
+       struct tapebuf *tpb = (struct tapebuf *) tapebuf;
+       struct s_spcl spclpt;
+
+       for (i = 0; i < ntrec; i++)
+               ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
+       blkcnt = 0;
+       tbufptr = tapebuf;
+       /*
+        * For a pipe or file, read in the first record. For a tape, read
+        * the first block.
+        */
+       len = magtapein ? ntrec * TP_BSIZE : TP_BSIZE;
+
+       if (read_a_block(mt, tapebuf, len, &i) <= 0)
+               errx(1, "Tape read error on first record");
+
+       memcpy(&spclpt, tapebuf, TP_BSIZE);
+       if (converthead(&spclpt) == FAIL) {
+               cvtflag++;
+               if (converthead(&spclpt) == FAIL) {
+                       /* Special case for old compressed tapes with prefix */
+                       if (magtapein && (i % TP_BSIZE != 0)) 
+                               goto oldformat;
+                       errx(1, "Tape is not a dump tape");
+               }
+               fprintf(stderr, "Converting to new file system format.\n");
+       }
+       /*
+        * If the input is from a file or a pipe, we read TP_BSIZE
+        * bytes looking for a dump header. If the dump is compressed
+        * we need to read in the rest of the block, as determined
+        * by c_ntrec in the dump header. The first block of the
+        * dump is not compressed and does not have a prefix.
+        */
+       if (!magtapein) {
+               if (spclpt.c_type == TS_TAPE
+                   && spclpt.c_flags & DR_COMPRESSED) {
+                       /* It's a compressed dump file, read in the */
+                       /* rest of the block based on spclpt.c_ntrec. */
+                       if (spclpt.c_ntrec > ntrec)
+                               errx(1, "Tape blocksize is too large, use "
+                                    "\'-b %d\' ", spclpt.c_ntrec);
+                       ntrec = spclpt.c_ntrec;
+                       len = (ntrec - 1) * TP_BSIZE;
+                       zflag = 1;   
+               }
+               else {
+                       /* read in the rest of the block based on bufsize */
+                       len = bufsize - TP_BSIZE;
+               }
+               if (read_a_block(mt, tapebuf+TP_BSIZE, len, &i) < 0
+                   || (i != (long)len && i % TP_BSIZE != 0))
+                       errx(1,"Error reading dump file header");
+               tbufptr = tapebuf;
+               numtrec = ntrec;
+               Vprintf(stdout, "Input block size is %ld\n", ntrec);
+               return;
+       } /* if (!magtapein) */
+
+       /*
+        * If the input is a tape, we tried to read ntrec * TP_BSIZE bytes.
+        * If the value of ntrec is too large, we read less than
+        * what we asked for; adjust the value of ntrec and test for 
+        * a compressed dump tape.
+        */
+       if (i % TP_BSIZE != 0) {
+oldformat:
+               /* may be old format compressed dump tape with a prefix */
+               memcpy(&spclpt, tpb->buf, TP_BSIZE);
+               cvtflag = 0;
+               if (converthead(&spclpt) == FAIL) {
+                       cvtflag++;
+                       if (converthead(&spclpt) == FAIL)
+                               errx(1, "Tape is not a dump tape");
+                       fprintf(stderr, "Converting to new file system format.\n");
+               }
+               if (i % TP_BSIZE == PREFIXSIZE
+                   && tpb->compressed == 0
+                   && spclpt.c_type == TS_TAPE
+                   && spclpt.c_flags & DR_COMPRESSED) {
+                       zflag = 1;
+                       tbufptr = tpb->buf;
+                       if (tpb->length > bufsize)
+                               errx(1, "Tape blocksize is too large, use "
+                                       "\'-b %d\' ", tpb->length / TP_BSIZE);
+               }
+               else
+                       errx(1, "Tape block size (%ld) is not a multiple of dump block size (%d)",
+                               i, TP_BSIZE);
+       }
+       ntrec = i / TP_BSIZE;
+       if (spclpt.c_type == TS_TAPE) {
+               if (spclpt.c_flags & DR_COMPRESSED)
+                       zflag = 1;
+               if (spclpt.c_ntrec > ntrec)
+                       errx(1, "Tape blocksize is too large, use "
+                               "\'-b %d\' ", spclpt.c_ntrec);
+       }
+       numtrec = ntrec;
+       Vprintf(stdout, "Tape block size is %ld\n", ntrec);
+}
+
+/*
+ * Read a block of data handling all of the messy details.
+ */
+static int read_a_block(int fd, char *buf, size_t len, long *lengthread)
+{
+       long i = 1, size;
+
+       size = len;
+       while (size > 0) {
+#ifdef RRESTORE
+               if (!Afile && host)
+                       i = rmtread(buf, size);
+               else
+#endif
+                       i = read(fd, buf, size);                 
+
+               if (i <= 0)
+                       break; /* EOD or error */
+               size -= i;
+               if (magtapein)
+                       break; /* block at a time for mt */
+               buf += i;
+       }
+       *lengthread = len - size;
+       return i;
+}
+
+void
+closemt(void)
+{
+
+       if (mt < 0)
+               return;
+#ifdef RRESTORE
+       if (!Afile && host)
+               rmtclose();
+       else
+#endif
+               (void) close(mt);
+}
+
+static void
+setmagtapein(void) {
+       struct mtget mt_stat;
+       static int done = 0;
+       if (done)
+               return;
+       done = 1;
+       if (!pipein) {
+               /* need to know if input is really from a tape */
+#ifdef RRESTORE
+               if (host)
+                       magtapein = !lflag;
+               else
+#endif
+                       magtapein = ioctl(mt, MTIOCGET, (char *)&mt_stat) == 0;
+       }
+
+       Vprintf(stdout,"Input is from a %s %s\n",
+                       host ? "remote" : "local",
+                       magtapein ? "tape" :
+                       Vflag ? "multi-volume (no tape)" : "file/pipe");
+}
+
+/*
+ * Read the next block from the tape.
+ * Check to see if it is one of several vintage headers.
+ * If it is an old style header, convert it to a new style header.
+ * If it is not any valid header, return an error.
+ */
+static int
+gethead(struct s_spcl *buf)
+{
+       readtape((char *)buf);
+       return converthead(buf);
+}
+
+static int
+converthead(struct s_spcl *buf)
+{
+       int32_t i;
+       union {
+               quad_t  qval;
+               int32_t val[2];
+       } qcvt;
+       union u_ospcl {
+               char dummy[TP_BSIZE];
+               struct  s_ospcl {
+                       int32_t c_type;
+                       int32_t c_date;
+                       int32_t c_ddate;
+                       int32_t c_volume;
+                       int32_t c_tapea;
+                       u_int16_t c_inumber;
+                       int32_t c_magic;
+                       int32_t c_checksum;
+                       struct odinode {
+                               u_int16_t odi_mode;
+                               u_int16_t odi_nlink;
+                               u_int16_t odi_uid;
+                               u_int16_t odi_gid;
+                               int32_t odi_size;
+                               int32_t odi_rdev;
+                               char    odi_addr[36];
+                               int32_t odi_atime;
+                               int32_t odi_mtime;
+                               int32_t odi_ctime;
+                       } c_dinode;
+                       int32_t c_count;
+                       char    c_fill[256];
+               } s_ospcl;
+       } u_ospcl;
+
+       if (!cvtflag) {
+               if (buf->c_magic != NFS_MAGIC) {
+                       if (swabi(buf->c_magic) != NFS_MAGIC)
+                               return (FAIL);
+                       if (!Bcvt) {
+                               Vprintf(stdout, "Note: Doing Byte swapping\n");
+                               Bcvt = 1;
+                       }
+               }
+               if (checksum((int *)buf) == FAIL)
+                       return (FAIL);
+               if (Bcvt)
+                       swabst((u_char *)"8i4s31i528bi192b3i", (u_char *)buf);
+               goto good;
+       }
+       memcpy(&u_ospcl.s_ospcl, buf, TP_BSIZE);
+       if (checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
+               return(FAIL);
+       if (u_ospcl.s_ospcl.c_magic == OFS_MAGIC) {
+               memset((char *)buf, 0, (long)TP_BSIZE);
+               buf->c_type = u_ospcl.s_ospcl.c_type;
+               buf->c_date = u_ospcl.s_ospcl.c_date;
+               buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
+               buf->c_volume = u_ospcl.s_ospcl.c_volume;
+               buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
+               buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
+               buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
+               buf->c_magic = u_ospcl.s_ospcl.c_magic;
+               buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
+               buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
+               buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
+               buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
+               buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
+               buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
+#if defined(__linux__) || defined(sunos)
+               buf->c_dinode.di_atime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
+               buf->c_dinode.di_mtime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
+               buf->c_dinode.di_ctime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
+#else  /* __linux__ || sunos */
+               buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
+               buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
+               buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
+#endif /* __linux__ || sunos */
+               buf->c_count = u_ospcl.s_ospcl.c_count;
+               memmove(buf->c_addr, u_ospcl.s_ospcl.c_fill, (long)256);
+       }
+       else if (u_ospcl.s_ospcl.c_magic == FS_UFS2_MAGIC) {
+               buf->c_date = (int32_t)(*(int64_t *)&u_ospcl.dummy[896]);
+               buf->c_ddate = (int32_t)(*(int64_t *)&u_ospcl.dummy[904]);
+               buf->c_tapea = (int32_t)(*(int64_t *)&u_ospcl.dummy[912]);
+               buf->c_firstrec = (int32_t)(*(int64_t *)&u_ospcl.dummy[920]);
+               buf->c_ntrec = 0;
+               buf->c_extattributes = 0;
+               buf->c_flags |= DR_NEWINODEFMT;
+               ufs2flag = 1;
+       }
+       else
+               return(FAIL);
+       buf->c_magic = NFS_MAGIC;
+
+good:
+       if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
+           (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
+               qcvt.qval = buf->c_dinode.di_size;
+               if (qcvt.val[0] || qcvt.val[1]) {
+                       Vprintf(stdout, "Note: Doing Quad swapping\n");
+                       Qcvt = 1;
+               }
+       }
+       if (Qcvt) {
+               qcvt.qval = buf->c_dinode.di_size;
+               i = qcvt.val[1];
+               qcvt.val[1] = qcvt.val[0];
+               qcvt.val[0] = i;
+               buf->c_dinode.di_size = qcvt.qval;
+       }
+       readmapflag = 0;
+
+       switch (buf->c_type) {
+
+       case TS_CLRI:
+       case TS_BITS:
+               /*
+                * Have to patch up missing information in bit map headers
+                */
+               buf->c_inumber = 0;
+               buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
+               if (buf->c_count > TP_NINDIR)
+                       readmapflag = 1;
+               else 
+                       for (i = 0; i < buf->c_count; i++)
+                               buf->c_addr[i]++;
+               break;
+
+       case TS_TAPE:
+               if ((buf->c_flags & DR_NEWINODEFMT) == 0)
+                       oldinofmt = 1;
+               /* fall through */
+       case TS_END:
+               buf->c_inumber = 0;
+               if (buf->c_flags & DR_INODEINFO) {
+                       memcpy(volinfo, buf->c_inos, TP_NINOS * sizeof(dump_ino_t));
+                       if (Bcvt)
+                               swabst((u_char *)"128i", (u_char *)volinfo);
+               }
+               break;
+
+       case TS_INODE:
+       case TS_ADDR:
+               break;
+
+       default:
+               panic("gethead: unknown inode type %d\n", buf->c_type);
+               break;
+       }
+       /*
+        * If we are restoring a filesystem with old format inodes,
+        * copy the uid/gid to the new location.
+        */
+       if (oldinofmt) {
+               buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
+               buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
+       }
+       if (dflag)
+               accthdr(buf);
+       return(GOOD);
+}
+
+static void
+converttapebuf(struct tapebuf *tpb)
+{
+       if (Bcvt) {
+               struct tb {
+                       unsigned int    length:28;
+                       unsigned int    flags:3;
+                       unsigned int    compressed:1;
+               } tb;
+               swabst((u_char *)"i", (u_char *)tpb);
+               memcpy(&tb, tpb, 4);    
+               tpb->length = tb.length;
+               tpb->flags = tb.flags;
+               tpb->compressed = tb.compressed;
+       }
+}
+
+/*
+ * Check that a header is where it belongs and predict the next header
+ */
+static void
+accthdr(struct s_spcl *header)
+{
+       static dump_ino_t previno = 0x7fffffff;
+       static int prevtype;
+       static long predict;
+       long blks, i;
+
+       if (header->c_type == TS_TAPE) {
+               fprintf(stderr, "Volume header (%s inode format) ",
+                   oldinofmt ? "old" : "new");
+               if (header->c_firstrec)
+                       fprintf(stderr, "begins with record %d",
+                               header->c_firstrec);
+               fprintf(stderr, "\n");
+               previno = 0x7fffffff;
+               return;
+       }
+       if (previno == 0x7fffffff)
+               goto newcalc;
+       switch (prevtype) {
+       case TS_BITS:
+               fprintf(stderr, "Dumped inodes map header");
+               break;
+       case TS_CLRI:
+               fprintf(stderr, "Used inodes map header");
+               break;
+       case TS_INODE:
+               fprintf(stderr, "File header, ino %lu", (unsigned long)previno);
+               break;
+       case TS_ADDR:
+               fprintf(stderr, "File continuation header, ino %ld", (long)previno);
+               break;
+       case TS_END:
+               fprintf(stderr, "End of tape header");
+               break;
+       }
+       if (predict != blksread - 1)
+               fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
+                       predict, blksread - 1);
+       fprintf(stderr, "\n");
+newcalc:
+       blks = 0;
+       if (header->c_type != TS_END)
+               for (i = 0; i < header->c_count; i++)
+                       if (readmapflag || header->c_addr[i] != 0)
+                               blks++;
+       predict = blks;
+       blksread = 0;
+       prevtype = header->c_type;
+       previno = header->c_inumber;
+}
+
+/*
+ * Find an inode header.
+ * Complain if had to skip, and complain is set.
+ */
+static void
+findinode(struct s_spcl *header)
+{
+       static long skipcnt = 0;
+       long i;
+       char buf[TP_BSIZE];
+
+       curfile.name = "<name unknown>";
+       curfile.action = UNKNOWN;
+       curfile.dip = NULL;
+       curfile.ino = 0;
+       do {
+               if (header->c_magic != NFS_MAGIC) {
+                       skipcnt++;
+                       while (gethead(header) == FAIL ||
+                           header->c_date != dumpdate)
+                               skipcnt++;
+               }
+               switch (header->c_type) {
+
+               case TS_ADDR:
+                       /*
+                        * Skip up to the beginning of the next record
+                        */
+                       for (i = 0; i < header->c_count; i++)
+                               if (header->c_addr[i])
+                                       readtape(buf);
+                       while (gethead(header) == FAIL ||
+                           header->c_date != dumpdate)
+                               skipcnt++;
+                       break;
+
+               case TS_INODE:
+                       curfile.dip = &header->c_dinode;
+                       curfile.ino = header->c_inumber;
+                       break;
+
+               case TS_END:
+                       curfile.ino = maxino;
+                       break;
+
+               case TS_CLRI:
+                       curfile.name = "<file removal list>";
+                       break;
+
+               case TS_BITS:
+                       curfile.name = "<file dump list>";
+                       break;
+
+               case TS_TAPE:
+                       panic("unexpected tape header\n");
+                       /* NOTREACHED */
+
+               default:
+                       panic("unknown tape header type %d\n", spcl.c_type);
+                       /* NOTREACHED */
+
+               }
+       } while (header->c_type == TS_ADDR);
+       if (skipcnt > 0)
+#ifdef USE_QFA
+               if (!noresyncmesg)
+#endif
+                       fprintf(stderr, "resync restore, skipped %ld blocks\n",
+                               skipcnt);
+       skipcnt = 0;
+}
+
+static int
+checksum(int *buf)
+{
+       int i, j;
+
+       j = sizeof(union u_spcl) / sizeof(int);
+       i = 0;
+       if(!Bcvt) {
+               do
+                       i += *buf++;
+               while (--j);
+       } else {
+               /* What happens if we want to read restore tapes
+                       for a 16bit int machine??? */
+               do
+                       i += swabi(*buf++);
+               while (--j);
+       }
+
+       if (i != CHECKSUM) {
+               fprintf(stderr, "Checksum error %o, inode %lu file %s\n", i,
+                       (unsigned long)curfile.ino, curfile.name);
+               return(FAIL);
+       }
+       return(GOOD);
+}
+
+#ifdef RRESTORE
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#ifdef __STDC__
+msg(const char *fmt, ...)
+#else
+msg(fmt, va_alist)
+       char *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void)vfprintf(stderr, fmt, ap);
+       va_end(ap);
+}
+#endif /* RRESTORE */
+
+static u_char *
+swab16(u_char *sp, int n)
+{
+       char c;
+
+       while (--n >= 0) {
+               c = sp[0]; sp[0] = sp[1]; sp[1] = c;
+               sp += 2;
+       }
+       return (sp);
+}
+
+static u_char *
+swab32(u_char *sp, int n)
+{
+       char c;
+
+       while (--n >= 0) {
+               c = sp[0]; sp[0] = sp[3]; sp[3] = c;
+               c = sp[1]; sp[1] = sp[2]; sp[2] = c;
+               sp += 4;
+       }
+       return (sp);
+}
+
+static u_char *
+swab64(u_char *sp, int n)
+{
+       char c;
+
+       while (--n >= 0) {
+               c = sp[0]; sp[0] = sp[7]; sp[7] = c;
+               c = sp[1]; sp[1] = sp[6]; sp[6] = c;
+               c = sp[2]; sp[2] = sp[5]; sp[5] = c;
+               c = sp[3]; sp[3] = sp[4]; sp[4] = c;
+               sp += 8;
+       }
+       return (sp);
+}
+
+void
+swabst(u_char *cp, u_char *sp)
+{
+       int n = 0;
+
+       while (*cp) {
+               switch (*cp) {
+               case '0': case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                       n = (n * 10) + (*cp++ - '0');
+                       continue;
+
+               case 's': case 'w': case 'h':
+                       if (n == 0)
+                               n = 1;
+                       sp = swab16(sp, n);
+                       break;
+
+               case 'i':
+                       if (n == 0)
+                               n = 1;
+                       sp = swab32(sp, n);
+                       break;
+
+               case 'l':
+                       if (n == 0)
+                               n = 1;
+                       sp = swab64(sp, n);
+                       break;
+
+               default: /* Any other character, like 'b' counts as byte. */
+                       if (n == 0)
+                               n = 1;
+                       sp += n;
+                       break;
+               }
+               cp++;
+               n = 0;
+       }
+}
+
+static u_int
+swabi(u_int x)
+{
+       swabst((u_char *)"i", (u_char *)&x);
+       return (x);
+}
+
+#if 0
+static u_long
+swabl(u_long x)
+{
+       swabst((u_char *)"l", (u_char *)&x);
+       return (x);
+}
+#endif
+
+void
+RequestVol(long tnum)
+{
+       FLUSHTAPEBUF();
+       getvol(tnum);
+}
+
+#ifdef USE_QFA
+#ifdef sunos
+extern int fdsmtc;
+
+struct uscsi_cmd {
+        int     uscsi_flags;            /* read, write, etc. see below */
+        short   uscsi_status;           /* resulting status  */
+        short   uscsi_timeout;          /* Command Timeout */
+        caddr_t uscsi_cdb;              /* cdb to send to target */
+        caddr_t uscsi_bufaddr;          /* i/o source/destination */
+        u_int   uscsi_buflen;           /* size of i/o to take place */
+        u_int   uscsi_resid;            /* resid from i/o operation */
+        u_char  uscsi_cdblen;           /* # of valid cdb bytes */
+        u_char  uscsi_rqlen;            /* size of uscsi_rqbuf */
+        u_char  uscsi_rqstatus;         /* status of request sense cmd */
+        u_char  uscsi_rqresid;          /* resid of request sense cmd */
+        caddr_t uscsi_rqbuf;            /* request sense buffer */
+        void   *uscsi_reserved_5;       /* Reserved for Future Use */
+};
+
+#define CDB_GROUP0      6       /*  6-byte cdb's */
+#define CDB_GROUP1      10      /* 10-byte cdb's */
+#define CDB_GROUP2      10      /* 10-byte cdb's */
+#define CDB_GROUP3      0       /* reserved */
+#define CDB_GROUP4      16      /* 16-byte cdb's */
+#define CDB_GROUP5      12      /* 12-byte cdb's */
+#define CDB_GROUP6      0       /* reserved */
+#define CDB_GROUP7      0       /* reserved */
+
+#define USCSI_WRITE     0x00000 /* send data to device */
+#define USCSI_SILENT    0x00001 /* no error messages */
+#define USCSI_DIAGNOSE  0x00002 /* fail if any error occurs */
+#define USCSI_ISOLATE   0x00004 /* isolate from normal commands */
+#define USCSI_READ      0x00008 /* get data from device */
+#define USCSI_RESET     0x04000 /* Reset target */
+#define USCSI_RESET_ALL 0x08000 /* Reset all targets */
+#define USCSI_RQENABLE  0x10000 /* Enable Request Sense extensions */
+
+#define USCSIIOC        (0x04 << 8)
+#define USCSICMD        (USCSIIOC|201)  /* user scsi command */
+
+#define USCSI_TIMEOUT  30
+#define USCSI_SHORT_TIMEOUT    900
+#define USCSI_LONG_TIMEOUT     14000
+
+#define B(s,i) ((unsigned char)((s) >> i))
+#define B1(s)                           ((unsigned char)(s))
+
+#define MSB4(s,v) *(s)=B(v,24),(s)[1]=B(v,16), (s)[2]=B(v,8), (s)[3]=B1(v)
+
+
+int
+GetTapePos(long long *pos)
+{
+       int                                     err = 0;
+       struct uscsi_cmd        scmd;
+       char                            buf[512];
+       char                            parm[512 * 8];
+       long                            lpos;
+
+       (void)memset((void *)buf, 0, sizeof(buf));
+       (void)memset((void *)&scmd, 0, sizeof(scmd));
+       scmd.uscsi_flags = USCSI_READ|USCSI_SILENT;
+       scmd.uscsi_timeout = USCSI_TIMEOUT;
+       scmd.uscsi_cdb = buf;
+       scmd.uscsi_cdblen = CDB_GROUP1;
+       buf[0] = 0x34;  /* read position */
+       buf[1] = 0;
+       (void)memset((void *)parm, 0, 512);
+       scmd.uscsi_bufaddr = parm;
+       scmd.uscsi_buflen = 56;
+       if (ioctl(fdsmtc, USCSICMD, &scmd) == -1) {
+               err = errno;
+               return err;
+       }
+       (void)memcpy(&lpos, &parm[4], sizeof(long));
+       *pos = lpos;
+       return err;
+}
+
+int
+GotoTapePos(long long pos)
+{
+       int                                     err = 0;
+       struct uscsi_cmd        scmd;
+       char                            buf[512];
+       char                            parm[512 * 8];
+       long                            lpos = (long)pos;
+
+       (void)memset((void *)buf, 0, sizeof(buf));
+       (void)memset((void *)&scmd, 0, sizeof(scmd));
+       scmd.uscsi_flags = USCSI_WRITE|USCSI_SILENT;
+       scmd.uscsi_timeout = 360;       /* 5 Minutes */
+       scmd.uscsi_cdb = buf;
+       scmd.uscsi_cdblen = CDB_GROUP1;
+       buf[0] = 0x2b;  /* locate */
+       buf[1] = 0;
+       MSB4(&buf[3], lpos);
+       (void)memset((void *)parm, 0, 512);
+       scmd.uscsi_bufaddr = NULL;
+       scmd.uscsi_buflen = 0;
+       if (ioctl(fdsmtc, USCSICMD, &scmd) == -1) {
+               err = errno;
+               return err;
+       }
+       return err;
+}
+#endif
+
+#define LSEEK_GET_TAPEPOS      10
+#define LSEEK_GO2_TAPEPOS      11
+
+#ifdef __linux__
+typedef struct mt_pos {
+       short    mt_op;
+       int      mt_count;
+} MTPosRec, *MTPosPtr;
+
+
+/*
+ * get the current position of the tape
+ */
+int
+GetTapePos(long long *pos)
+{
+       int err = 0;
+
+#ifdef RDUMP
+       if (host) {
+               *pos = (long long) rmtseek((OFF_T)0, (int)LSEEK_GET_TAPEPOS);
+               err = *pos < 0;
+       }
+       else
+#endif
+       {
+       if (magtapein) {
+               long mtpos;
+               *pos = 0;
+               err = (ioctl(mt, MTIOCPOS, &mtpos) < 0);
+               *pos = (long long)mtpos;
+       }
+       else {
+               *pos = LSEEK(mt, 0, SEEK_CUR);
+               err = (*pos < 0);
+       }
+       }
+       if (err) {
+               err = errno;
+               fprintf(stdout, "[%ld] error: %d (getting tapepos: %lld)\n", 
+                       (unsigned long)getpid(), err, *pos);
+               return err;
+       }
+       return err;
+}
+
+/*
+ * go to specified position on tape
+ */
+int
+GotoTapePos(long long pos)
+{
+       int err = 0;
+
+#ifdef RDUMP
+       if (host)
+               err = (rmtseek((OFF_T)pos, (int)LSEEK_GO2_TAPEPOS) < 0);
+       else
+#endif
+       {
+       if (magtapein) {
+               struct mt_pos buf;
+               buf.mt_op = MTSEEK;
+               buf.mt_count = (int) pos;
+               err = (ioctl(mt, MTIOCTOP, &buf) < 0);
+       }
+       else {
+               pos = LSEEK(mt, pos, SEEK_SET);
+               err = (pos < 0);
+       }
+       }
+       if (err) {
+               err = errno;
+               fprintf(stdout, "[%ld] error: %d (setting tapepos: %lld)\n", 
+                       (unsigned long)getpid(), err, pos);
+               return err;
+       }
+       return err;
+}
+#endif /* __linux__ */
+
+/*
+ * read next data from tape to re-sync
+ */
+void
+ReReadFromTape(void)
+{
+       FLUSHTAPEBUF();
+       noresyncmesg = 1;
+       if (gethead(&spcl) == FAIL) {
+#ifdef DEBUG_QFA
+               fprintf(stdout, "DEBUG 1 gethead failed\n");
+#endif
+       }
+       findinode(&spcl);
+       noresyncmesg = 0;
+}
+
+void
+ReReadInodeFromTape(dump_ino_t theino)
+{
+       long    cntloop = 0;
+
+       FLUSHTAPEBUF();
+       noresyncmesg = 1;
+       do {
+               cntloop++;
+               gethead(&spcl);
+       } while (!(spcl.c_inumber == theino && spcl.c_type == TS_INODE && spcl.c_date == dumpdate));
+#ifdef DEBUG_QFA
+       fprintf(stderr, "DEBUG: %ld reads\n", cntloop);
+       fprintf(stderr, "DEBUG: bufsize %ld\n", bufsize);
+       fprintf(stderr, "DEBUG: ntrec %ld\n", ntrec);
+       fprintf(stderr, "DEBUG: %ld reads\n", cntloop);
+#endif
+       findinode(&spcl);
+       noresyncmesg = 0;
+}
+
+#ifdef sunos
+int
+OpenSMTCmt(char *themagtape)
+{
+       if (GetSCSIIDFromPath(themagtape, &scsiid)) {
+               fprintf(stderr, "can't get SCSI-ID for %s\n", themagtape);
+               return -1;
+       }
+       if (scsiid < 0) {
+               fprintf(stderr, "can't get SCSI-ID for %s\n", themagtape);
+               return -1;
+       }
+       sprintf(smtcpath, "/dev/rsmtc%ld,0", scsiid);
+       if ((fdsmtc = open(smtcpath, O_RDWR)) == -1) {
+               fprintf(stderr, "can't open smtc device: %s, %d\n", smtcpath, errno);
+               return -1;
+       }
+       return 0;
+}
+#endif /* sunos */
+#endif /* USE_QFA */
diff --git a/restore/utilities.c b/restore/utilities.c
new file mode 100644 (file)
index 0000000..e0db9af
--- /dev/null
@@ -0,0 +1,720 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: utilities.c,v 1.24 2003/11/22 16:52:16 stelian Exp $";
+#endif /* not lint */
+
+#include <config.h>
+#include <compatlfs.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <compaterr.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#include <sys/time.h>
+#include <time.h>
+#include <fcntl.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+#include <ext2fs/ext2fs.h>
+#include <bsdcompat.h>
+#else  /* __linux__ */
+#ifdef sunos
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <bsdcompat.h>
+#else
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#endif
+#endif /* __linux__ */
+#ifdef DUMP_MACOSX
+#include "darwin.h"
+#endif
+#include "restore.h"
+#include "extern.h"
+
+/*
+ * Insure that all the components of a pathname exist.
+ */
+void
+pathcheck(char *name)
+{
+       char *cp;
+       struct entry *ep;
+       char *start;
+
+       start = strchr(name, '/');
+       if (start == 0)
+               return;
+       for (cp = start; *cp != '\0'; cp++) {
+               if (*cp != '/')
+                       continue;
+               *cp = '\0';
+               ep = lookupname(name);
+               if (ep == NULL) {
+                       /* Safe; we know the pathname exists in the dump. */
+                       ep = addentry(name, pathsearch(name)->d_ino, NODE);
+                       newnode(ep);
+               }
+               ep->e_flags |= NEW|KEEP;
+               *cp = '/';
+       }
+}
+
+/*
+ * Change a name to a unique temporary name.
+ */
+void
+mktempname(struct entry *ep)
+{
+       char oldname[MAXPATHLEN];
+
+       if (ep->e_flags & TMPNAME)
+               badentry(ep, "mktempname: called with TMPNAME");
+       ep->e_flags |= TMPNAME;
+       (void) strcpy(oldname, myname(ep));
+       freename(ep->e_name);
+       ep->e_name = savename(gentempname(ep));
+       ep->e_namlen = strlen(ep->e_name);
+       renameit(oldname, myname(ep));
+}
+
+/*
+ * Generate a temporary name for an entry.
+ */
+char *
+gentempname(struct entry *ep)
+{
+       static char name[MAXPATHLEN];
+       struct entry *np;
+       long i = 0;
+
+       for (np = lookupino(ep->e_ino);
+           np != NULL && np != ep; np = np->e_links)
+               i++;
+       if (np == NULL)
+               badentry(ep, "not on ino list");
+       (void) snprintf(name, sizeof(name), "%s%ld%lu", TMPHDR, i, (unsigned long)ep->e_ino);
+       return (name);
+}
+
+/*
+ * Rename a file or directory.
+ */
+void
+renameit(char *from, char *to)
+{
+       if (!Nflag && rename(from, to) < 0) {
+               warn("cannot rename %s to %s", from, to);
+               return;
+       }
+       Vprintf(stdout, "rename %s to %s\n", from, to);
+}
+
+/*
+ * Create a new node (directory).
+ */
+void
+newnode(struct entry *np)
+{
+       char *cp;
+       if (np->e_type != NODE)
+               badentry(np, "newnode: not a node");
+       cp = myname(np);
+       if (command == 'C') return;
+
+       if (!Nflag && mkdir(cp, 0777) < 0 && !uflag) {
+               np->e_flags |= EXISTED;
+               warn("%s", cp);
+               return;
+       }
+       Vprintf(stdout, "Make node %s\n", cp);
+}
+
+/*
+ * Remove an old node (directory).
+ */
+void
+removenode(struct entry *ep)
+{
+       char *cp;
+
+       if (ep->e_type != NODE)
+               badentry(ep, "removenode: not a node");
+       if (ep->e_entries != NULL)
+               badentry(ep, "removenode: non-empty directory");
+       ep->e_flags |= REMOVED;
+       ep->e_flags &= ~TMPNAME;
+       cp = myname(ep);
+       if (!Nflag && rmdir(cp) < 0) {
+               warn("%s", cp);
+               return;
+       }
+       Vprintf(stdout, "Remove node %s\n", cp);
+}
+
+/*
+ * Remove a leaf.
+ */
+void
+removeleaf(struct entry *ep)
+{
+       char *cp;
+
+       if (command == 'C') return;
+
+       if (ep->e_type != LEAF)
+               badentry(ep, "removeleaf: not a leaf");
+       ep->e_flags |= REMOVED;
+       ep->e_flags &= ~TMPNAME;
+       cp = myname(ep);
+       if (!Nflag && unlink(cp) < 0) {
+               warn("%s", cp);
+               return;
+       }
+       Vprintf(stdout, "Remove leaf %s\n", cp);
+}
+
+/*
+ * Create a link.
+ */
+int
+linkit(char *existing, char *new, int type)
+{
+
+       /* if we want to unlink first, do it now so *link() won't fail */
+       if (uflag && !Nflag)
+               (void)unlink(new);
+
+       if (type == SYMLINK) {
+               if (!Nflag && symlink(existing, new) < 0) {
+                       warn("cannot create symbolic link %s->%s",
+                           new, existing);
+                       return (FAIL);
+               }
+       } else if (type == HARDLINK) {
+               int ret;
+
+               if (!Nflag && (ret = link(existing, new)) < 0) {
+
+#if !defined(__linux__) && !defined(sunos)
+                       struct stat s;
+
+                       /*
+                        * Most likely, the schg flag is set.  Clear the
+                        * flags and try again.
+                        */
+                       if (stat(existing, &s) == 0 && s.st_flags != 0 &&
+                           chflags(existing, 0) == 0) {
+                               ret = link(existing, new);
+                               chflags(existing, s.st_flags);
+                       }
+#else
+                       unsigned long s;
+
+                       /*
+                        * Most likely, the immutable or append-only attribute
+                        * is set. Clear the attributes and try again.
+                        */
+#ifdef sunos
+#else
+                       if (fgetflags (existing, &s) != -1 &&
+                           fsetflags (existing, 0) != -1) {
+                               ret = link(existing, new);
+                               fsetflags(existing, s);
+                       }
+#endif
+#endif
+                       if (ret < 0) {
+                               warn("warning: cannot create hard link %s->%s",
+                                   new, existing);
+                               return (FAIL);
+                       }
+               }
+       } else {
+               panic("linkit: unknown type %d\n", type);
+               return (FAIL);
+       }
+       Vprintf(stdout, "Create %s link %s->%s\n",
+               type == SYMLINK ? "symbolic" : "hard", new, existing);
+       return (GOOD);
+}
+
+#if !defined(__linux__) && !defined(sunos)
+/*
+ * Create a whiteout.
+ */
+int
+addwhiteout(char *name)
+{
+
+       if (!Nflag && mknod(name, S_IFWHT, 0) < 0) {
+               warn("cannot create whiteout %s", name);
+               return (FAIL);
+       }
+       Vprintf(stdout, "Create whiteout %s\n", name);
+       return (GOOD);
+}
+
+/*
+ * Delete a whiteout.
+ */
+void
+delwhiteout(struct entry *ep)
+{
+       char *name;
+
+       if (ep->e_type != LEAF)
+               badentry(ep, "delwhiteout: not a leaf");
+       ep->e_flags |= REMOVED;
+       ep->e_flags &= ~TMPNAME;
+       name = myname(ep);
+       if (!Nflag && undelete(name) < 0) {
+               warn("cannot delete whiteout %s", name);
+               return;
+       }
+       Vprintf(stdout, "Delete whiteout %s\n", name);
+}
+#endif
+
+/*
+ * find lowest number file (above "start") that needs to be extracted
+ */
+dump_ino_t
+lowerbnd(dump_ino_t start)
+{
+       struct entry *ep;
+
+       for ( ; start < maxino; start++) {
+               ep = lookupino(start);
+               if (ep == NULL || ep->e_type == NODE)
+                       continue;
+               if (ep->e_flags & (NEW|EXTRACT))
+                       return (start);
+       }
+       return (start);
+}
+
+/*
+ * find highest number file (below "start") that needs to be extracted
+ */
+dump_ino_t
+upperbnd(dump_ino_t start)
+{
+       struct entry *ep;
+
+       for ( ; start > ROOTINO; start--) {
+               ep = lookupino(start);
+               if (ep == NULL || ep->e_type == NODE)
+                       continue;
+               if (ep->e_flags & (NEW|EXTRACT))
+                       return (start);
+       }
+       return (start);
+}
+
+/*
+ * report on a badly formed entry
+ */
+void
+badentry(struct entry *ep, const char *msg)
+{
+
+       fprintf(stderr, "bad entry: %s\n", msg);
+       fprintf(stderr, "name: %s\n", myname(ep));
+       fprintf(stderr, "parent name %s\n", myname(ep->e_parent));
+       if (ep->e_sibling != NULL)
+               fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling));
+       if (ep->e_entries != NULL)
+               fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries));
+       if (ep->e_links != NULL)
+               fprintf(stderr, "next link name: %s\n", myname(ep->e_links));
+       if (ep->e_next != NULL)
+               fprintf(stderr,
+                   "next hashchain name: %s\n", myname(ep->e_next));
+       fprintf(stderr, "entry type: %s\n",
+               ep->e_type == NODE ? "NODE" : "LEAF");
+       fprintf(stderr, "inode number: %lu\n", (unsigned long)ep->e_ino);
+       panic("flags: %s\n", flagvalues(ep));
+}
+
+/*
+ * Construct a string indicating the active flag bits of an entry.
+ */
+char *
+flagvalues(struct entry *ep)
+{
+       static char flagbuf[BUFSIZ];
+
+       (void) strcpy(flagbuf, "|NIL");
+       flagbuf[0] = '\0';
+       if (ep->e_flags & REMOVED)
+               (void) strcat(flagbuf, "|REMOVED");
+       if (ep->e_flags & TMPNAME)
+               (void) strcat(flagbuf, "|TMPNAME");
+       if (ep->e_flags & EXTRACT)
+               (void) strcat(flagbuf, "|EXTRACT");
+       if (ep->e_flags & NEW)
+               (void) strcat(flagbuf, "|NEW");
+       if (ep->e_flags & KEEP)
+               (void) strcat(flagbuf, "|KEEP");
+       if (ep->e_flags & EXISTED)
+               (void) strcat(flagbuf, "|EXISTED");
+       return (&flagbuf[1]);
+}
+
+/*
+ * Check to see if a name is on a dump tape.
+ */
+dump_ino_t
+dirlookup(const char *name)
+{
+       struct direct *dp;
+       dump_ino_t ino;
+
+       ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino;
+
+       if (ino == 0 || TSTINO(ino, dumpmap) == 0)
+               fprintf(stderr, "%s is not on the tape\n", name);
+       return (ino);
+}
+
+/*
+ * Elicit a reply.
+ */
+int
+reply(const char *question)
+{
+       char c;
+
+       do      {
+               fprintf(stderr, "%s? [yn] ", question);
+               (void) fflush(stderr);
+               c = getc(terminal);
+               while (c != '\n' && getc(terminal) != '\n')
+                       if (feof(terminal))
+                               return (FAIL);
+       } while (c != 'y' && c != 'n');
+       if (c == 'y')
+               return (GOOD);
+       return (FAIL);
+}
+
+/*
+ * handle unexpected inconsistencies
+ */
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#ifdef __STDC__
+panic(const char *fmt, ...)
+#else
+panic(fmt, va_alist)
+       char *fmt;
+       va_dcl
+#endif
+{
+       va_list ap;
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+
+       vfprintf(stderr, fmt, ap);
+       if (yflag)
+               return;
+       if (reply("abort") == GOOD) {
+               if (reply("dump core") == GOOD)
+                       abort();
+               exit(1);
+       }
+}
+
+void resizemaps(dump_ino_t oldmax, dump_ino_t newmax)
+{
+       char *map;
+
+       if (usedinomap) {
+               map = calloc((unsigned)1, (unsigned)howmany(newmax, NBBY));
+               if (map == NULL)
+                       errx(1, "no memory for active inode map");
+               memcpy(map, usedinomap, howmany(oldmax, NBBY));
+               free(usedinomap);
+               usedinomap = map;
+       }
+       if (dumpmap) {
+               map = calloc((unsigned)1, (unsigned)howmany(newmax, NBBY));
+               if (map == NULL)
+                       errx(1, "no memory for file dump list");
+               memcpy(map, dumpmap, howmany(oldmax, NBBY));
+               free(dumpmap);
+               dumpmap = map;
+       }
+}
+
+void
+GetPathFile(char *source, char *path, char *fname)
+{
+       char *p, *s;
+
+       *path = 0;
+       *fname = 0;
+       p = s = source;
+       while (*s) {
+               if (*s == '/') {
+                       p = s + 1;
+               }
+               s++;
+       }
+       if (p == source) {
+               *path = 0;
+       } else {
+               strncpy(path, source, p - source);
+               path[p - source] = 0;
+       }
+       strcpy(fname, p);
+}
+
+#ifdef USE_QFA
+/*
+ * search for ino in QFA file
+ *
+ * if exactmatch:
+ * if ino found return tape number and tape position
+ * if ino not found return tnum=0 and tpos=0
+ *
+ * if not exactmatch:
+ * if ino found return tape number and tape position
+ * if ino not found return tape number and tape position of last smaller ino
+ * if no smaller inode found return tnum=0 and tpos=0
+ */
+int
+Inode2Tapepos(dump_ino_t ino, long *tnum, long long *tpos, int exactmatch)
+{
+       char *p, *pp;
+       char numbuff[32];
+       unsigned long tmpino;
+       long tmptnum;
+       long long tmptpos;
+
+       *tpos = 0;
+       *tnum = 0;
+       if (fseek(gTapeposfp, gSeekstart, SEEK_SET) == -1)
+               return errno;
+       while (1) {
+               gSeekstart = ftell(gTapeposfp); /* remember for later use */
+               if (fgets(gTps, sizeof(gTps), gTapeposfp) == NULL) {
+                       return 0;
+               }
+               gTps[strlen(gTps) - 1] = 0;     /* delete end of line */
+               p = gTps;
+               bzero(numbuff, sizeof(numbuff));
+               pp = numbuff;
+               /* read inode */
+               while ((*p != 0) && (*p != '\t'))
+                       *pp++ = *p++;
+               tmpino = atol(numbuff);
+               if (*p == 0)
+                       return 1;       /* may NOT happen */    
+               p++;
+               bzero(numbuff, sizeof(numbuff));
+               pp = numbuff;
+               /* read tapenum */
+               while ((*p != 0) && (*p != '\t'))
+                       *pp++ = *p++;
+               if (*p == 0)
+                       return 1;       /* may NOT happen */    
+               tmptnum = atol(numbuff);
+               p++;
+               bzero(numbuff, sizeof(numbuff));
+               pp = numbuff;
+               /* read tapepos */
+               while ((*p != 0) && (*p != '\t'))
+                       *pp++ = *p++;
+               tmptpos = atoll(numbuff);
+
+               if (exactmatch) {
+                       if (tmpino == ino)  {
+                               *tnum = tmptnum;
+                               *tpos = tmptpos;
+                               return 0;
+                       }
+               } else {
+                       if (tmpino > ino)  {
+                               return 0;
+                       } else {
+                               *tnum = tmptnum;
+                               *tpos = tmptpos;
+                       }
+               }
+       }
+       return 0;
+}
+
+#ifdef sunos
+int
+GetSCSIIDFromPath(char *devPath, long *id)
+{
+       int     len;
+       char    fbuff[2048];
+       char    path[2048];
+       char    fname[2048];
+       char    *fpn = fname;
+       char    idstr[32];
+       char    *ip = idstr;
+
+       bzero(fbuff, sizeof(fbuff));
+       if ((len = readlink(devPath, fbuff, 2048)) == -1) {
+               return errno;
+       }
+       fbuff[len] = 0;
+       GetPathFile(fbuff, path, fname);
+       (void)memset(idstr, 0, sizeof(idstr));
+       while (*fpn && (*fpn != ',')) {
+               if (*fpn <= '9' && *fpn >= '0') {
+                       *ip = *fpn;
+                       ip++;
+               }
+               fpn++;
+       }
+       if (*idstr) {
+               *id = atol(idstr);
+       } else {
+               *id = -1;
+       }
+       return 0;
+}
+#endif
+#endif /* USE_QFA */
+
+#ifdef DUMP_MACOSX
+int
+CreateAppleDoubleFileRes(char *oFile, FndrFileInfo *finderinfo, mode_t mode, int flags,
+               struct timeval *timep, u_int32_t uid, u_int32_t gid)
+{
+       int             err = 0;
+       int             fdout;
+       char            *p;
+       char            *pp;
+       ASDHeaderPtr    hp;
+       ASDEntryPtr     ep;
+       long            thesize;
+       long            n;
+
+
+       n = 1;  /* number of entries in double file ._ only finderinfo */
+       /*
+       no data fork
+       n++;
+       currently no resource fork
+       n++;
+       */
+
+       thesize = sizeof(ASDHeader) + (n * sizeof(ASDEntry)) + INFOLEN;
+       if ((pp = p = (char *)malloc(thesize)) == NULL) {
+               err = errno;
+               return err;
+       }
+
+       hp = (ASDHeaderPtr)p;
+       p += sizeof(ASDHeader);
+       ep = (ASDEntryPtr)p;
+       p += sizeof(ASDEntry) * n;
+
+       hp->magic = ADOUBLE_MAGIC;
+       hp->version = ASD_VERSION2;
+
+       bzero(&hp->filler, sizeof(hp->filler));
+       hp->entries = (short)n;
+       
+       ep->entryID = EntryFinderInfo;
+       ep->offset = p - pp - CORRECT;
+       ep->len = INFOLEN; /*  sizeof(MacFInfo) + sizeof(FXInfo); */
+       bzero(p, ep->len);
+       bcopy(finderinfo, p, sizeof(FndrFileInfo));
+       p += ep->len;
+       ep++;
+
+       if ((fdout = open(oFile, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
+               err = errno;
+               free(pp);
+               return err;
+       }
+
+       /* write the ASDHeader */
+       if (write(fdout, pp, sizeof(ASDHeader) - CORRECT) == -1) {
+               err = errno;
+               close(fdout);
+               free(pp);
+               unlink(oFile);
+               return err;
+       }
+       /* write the ASDEntries */
+       if (write(fdout, pp + sizeof(ASDHeader), thesize - sizeof(ASDHeader)) == -1) {
+               err = errno;
+               close(fdout);
+               free(pp);
+               unlink(oFile);
+               return err;
+       }
+
+       (void)fchown(fdout, uid, gid);
+       (void)fchmod(fdout, mode);
+       close(fdout);
+       (void)fsetflags(oFile, flags);
+       utimes(oFile, timep);
+       free(pp);
+       return err;
+}
+#endif /* DUMP_MACOSX */
diff --git a/rmt/Makefile.in b/rmt/Makefile.in
new file mode 100644 (file)
index 0000000..f64f5fa
--- /dev/null
@@ -0,0 +1,53 @@
+# $Id: Makefile.in,v 1.10 2003/05/08 21:11:39 stelian Exp $
+
+top_srcdir=    @top_srcdir@
+srcdir=                @srcdir@
+top_builddir=  ..
+
+@MCONFIG@
+
+ALL_CFLAGS=    @CPPFLAGS@ @CFLAGS@ @CCOPTS@ -pipe $(OPT) $(GINC) $(INC) $(DEFS)
+ALL_LDFLAGS=   @LDFLAGS@ @LDOPTS@ @STATIC@
+LIBS=          $(GLIBS)
+DEPLIBS=       ../compat/lib/libcompat.a
+
+PROG=          rmt
+SRCS=          rmt.c
+OBJS=          rmt.o
+MAN8=          rmt.8
+
+.c.o:
+       $(CC) -c $(ALL_CFLAGS) $< -o $@
+
+all::          $(PROG) @ERMT@ $(MAN8)
+
+$(PROG):       $(OBJS) $(DEPLIBS)
+       $(LD) $(ALL_LDFLAGS) -o $(PROG) $(OBJS) $(LIBS)
+
+ermt:  ermt.o cipher.o $(DEPLIBS)
+       $(LD) $(ALL_LDFLAGS) -o ermt ermt.o cipher.o $(LIBS) @CRYPTO@
+
+ermt.o: rmt.c
+       $(CC) -c $(ALL_CFLAGS) -DERMT -o ermt.o rmt.c
+
+$(MAN8):               rmt.8.in
+       sed -e "s|__DATE__|$(DATE)|g" \
+           -e "s|__VERSION__|$(VERSION)|g" $< > $@
+
+install::      all
+       $(INSTALL) -d $(SBINDIR) $(MANDIR)
+       $(INSTALLBIN) $(PROG) $(SBINDIR)
+       $(INSTALLMAN) $(srcdir)/$(MAN8) $(MANDIR)
+
+clean::
+       rm -f $(PROG) @ERMT@ \#* *.s *.o *.a *~ core rmt.8
+
+distclean::    clean
+       rm -f Makefile Makefile.old .depend 
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+
diff --git a/rmt/cipher.c b/rmt/cipher.c
new file mode 100644 (file)
index 0000000..48da098
--- /dev/null
@@ -0,0 +1,131 @@
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <strings.h>
+#include <errno.h>
+#include <openssl/evp.h>
+
+/*
+ * Encrypt or decrypt buf, returning a pointer to the transformed data,
+ * or NULL on error.
+ * The returned data is the same size as the input data,
+ * which means we must turn off cipher padding, and require that buflen
+ * be a multiple of the cipher block size (8 for Blowfish).
+ * To keep things simple, the return value is a malloc'd
+ * buffer that is overwritten on each call.
+ *
+ * Ken Lalonde <ken@globalremit.com>, 2003
+ */
+char *
+cipher(char *buf, int buflen, int do_encrypt)
+{
+       static EVP_CIPHER_CTX ctx;
+       static char *out = NULL;        /* return value, grown as necessary */
+       static int outlen = 0;
+       static int init = 0, which, blocksize;
+       int n;
+
+       if (!init) {
+               static const EVP_CIPHER *cipher;
+               unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
+               // Read key from $HOME/.ermt.key
+               char *keyfile = ".ermt.key";
+               unsigned char buf[128];
+               FILE *fp;
+               int i;
+
+               openlog("ermt", LOG_PID, LOG_DAEMON);
+               // Not needed: OpenSSL_add_all_algorithms();
+               // Not needed: ERR_load_crypto_strings();
+               cipher = EVP_bf_cbc();  // or: EVP_aes_{128,192,256}_cbc()
+               // We want the ability to decrypt the output
+               // using "openssl enc -d -kfile K -nopad -nosalt", which
+               // means we must read the key file the same way
+               // openssl does.  But be careful: if the key contains
+               // \0 or \r or \n, the effective size will be reduced.
+               if ((fp = fopen(keyfile, "r")) == NULL) {
+                       syslog(LOG_ERR, "Can't open key file %s: %m", keyfile);
+                       return NULL;
+               }
+               buf[0] = '\0';
+               fgets(buf, sizeof buf, fp);
+               fclose(fp);
+               i = strlen(buf);
+               if ((i > 0) &&
+                       ((buf[i-1] == '\n') || (buf[i-1] == '\r')))
+                       buf[--i]='\0';
+               if ((i > 0) &&
+                       ((buf[i-1] == '\n') || (buf[i-1] == '\r')))
+                       buf[--i]='\0';
+               if (i < 1) {
+                       syslog(LOG_ERR, "zero length key");
+                       errno = EINVAL;
+                       return NULL;
+               }
+               EVP_BytesToKey(cipher, EVP_md5(), NULL,
+                       buf, strlen(buf), 1, key, iv);
+               EVP_CIPHER_CTX_init(&ctx);
+               EVP_CipherInit_ex(&ctx, cipher, NULL, key, iv, do_encrypt);
+               EVP_CIPHER_CTX_set_padding(&ctx, 0);    // -nopad
+               OPENSSL_cleanse(buf, sizeof buf);
+               OPENSSL_cleanse(key, sizeof key);
+               OPENSSL_cleanse(iv, sizeof iv);
+               blocksize = EVP_CIPHER_CTX_block_size(&ctx);
+               which = do_encrypt;
+               init = 1;
+       }
+       if (which != do_encrypt) {
+               syslog(LOG_ERR, "Cannot switch modes");
+               errno = EINVAL;
+               return NULL;
+       }
+       if ((buflen % blocksize) != 0) {
+               syslog(LOG_ERR, "Buffer size is not a multiple of cipher block size");
+               errno = EINVAL;
+               return NULL;
+       }
+       if (outlen < buflen+blocksize) {
+               outlen = (buflen+blocksize) * 2;
+               out = realloc(out, outlen);
+       }
+       if (!EVP_CipherUpdate(&ctx, out, &n, buf, buflen)) {
+               syslog(LOG_ERR, "EVP_CipherUpdate failed");
+               errno = EINVAL;
+               return NULL;
+       }
+       if (n != buflen) {
+               syslog(LOG_ERR, "EVP_CipherUpdate: %d != %d", n, buflen);
+               errno = EINVAL;
+               return NULL;
+       }
+       // assert(ctx->buf_len == 0);
+       return out;
+}
+
+/* Decrypt stdin to stdout, and exit */
+int
+decrypt()
+{
+       char buf[8*1024], *cp;
+       int n;
+
+       while ((n = fread(buf, 1, sizeof buf, stdin)) > 0) {
+               if ((cp = cipher(buf, n, 0)) == NULL) {
+                       fprintf(stderr, "ermt: Error decoding input; see daemon.err syslog\n");
+                       exit(1);
+               }
+               fwrite(cp, 1, n, stdout);
+       }
+       if (ferror(stdin)) {
+               perror("ermt: stdin: read");
+               exit(1);
+       }
+       if (fflush(stdout)) {
+               perror("ermt: stdout: write");
+               exit(1);
+       }
+       exit(0);
+}
diff --git a/rmt/rmt.8.in b/rmt/rmt.8.in
new file mode 100644 (file)
index 0000000..af41e0a
--- /dev/null
@@ -0,0 +1,365 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     $Id: rmt.8.in,v 1.10 2003/03/30 15:40:40 stelian Exp $
+.\"
+.TH RMT 8 "version __VERSION__ of __DATE__" BSD "System management commands"
+.SH NAME
+rmt \- remote magtape protocol module
+.SH SYNOPSIS
+.B rmt
+.SH DESCRIPTION
+.B Rmt
+is a program used by the remote 
+.BR dump (8),
+.BR restore (8)
+or
+.BR tar (1)
+programs in manipulating a magnetic tape drive through an interprocess
+communication connection.
+.B Rmt
+is normally started up with an
+.BR rexec (3)
+or
+.BR rcmd (3)
+call.
+.PP
+The 
+.B rmt
+program accepts requests specific to the manipulation of magnetic tapes, 
+performs the commands, then responds with a status indication.  All responses 
+are in
+.B ASCII
+and in one of the following two forms.
+.PP
+Successful commands have responses of:
+.RS
+.B A\fInumber\fR\en
+.RE
+.PP
+where
+.I number
+is an
+.B ASCII
+representation of a decimal number.
+.PP
+Unsuccessful commands are responded to with:
+.RS
+.B E\fIerror-number\fR\en\fIerror-message\fR\en
+.RE
+.PP
+where 
+.I error-number
+is one of the possible error numbers described in
+.BR intro (2)
+and
+.I error-message
+is the corresponding error string as printed from a call to
+.BR perror (3).
+.PP
+The protocol is comprised of the following commands, which are sent as 
+indicated - no spaces are supplied between the command and its arguments, or
+between its arguments, and \en indicates that a newline should be supplied:
+.TP
+.B O\fIdevice\fR\en\fImode\fR\en
+Open the specified 
+.I device
+using the indicated
+.IR mode .
+.I Device
+is a full pathname and
+.I mode
+is an
+.B ASCII
+representation of a decimal number suitable for passing to
+.BR open (2).
+If a device had already been opened, it is closed before a new open is
+performed.
+.TP
+.B C\fIdevice\fR\en
+Close the currently open device.  The
+.I device
+specified is ignored.
+.TP
+.B L\fIwhence\fR\en\fIoffset\fR\en
+Perform an
+.BR lseek (2)
+operation using the specified parameters. The response value is that returned
+from the
+.B lseek
+call.
+.TP
+.B W\fIcount\fR\en
+Write data onto the open device.
+.B Rmt
+reads
+.I count
+bytes from the connection, aborting if a premature end-of-file is encountered.
+The response value is that returned from the
+.BR write (2)
+call.
+.TP
+.B R\fIcount\fR\en
+Read
+.I count
+bytes of data from the open device. If
+.I count
+exceeds the size of the data buffer (10 kilobytes), it is truncated to the 
+data buffer size.
+.B Rmt
+then performs the requested 
+.BR read (2)
+and responds with 
+.B A\fIcount-read\fR\en
+if the read was successful; otherwise an error in the standard format is 
+returned. If the read was successful, the data read is then sent.
+.TP
+.B I\fIoperation\fR\en\fIcount\fR\en
+Perform a
+.B MTIOCOP
+.BR ioctl (2)
+command using the specified parameters.  The parameters are interpreted as the
+.B ASCII
+representations of the decimal values to place in the 
+.B mt_op
+and
+.B mt_count
+fields of the structure used in the
+.B ioctl
+call.  The return value is the
+.I count
+parameter when the operation is successful.
+.IP
+By issuing the
+.B I-1\en0\en
+command, a client will specify that he is using the VERSION 1 protocol.
+.IP
+For a VERSION 0 client, the
+.I operation
+parameter is the platform 
+.B mt_op
+value (could be different if the client and the
+.B rmt
+server are on two different platforms). For a VERSION 1 client, the 
+.I operation
+parameter is standardized as below:
+.RS
+.TP
+.B 0
+Issue a 
+.B MTWEOF
+command (write
+.I count
+end-of-file records).
+.TP
+.B 1
+Issue a 
+.B MTFSF
+command (forward space over
+.I count
+file marks).
+.TP
+.B 2
+Issue a 
+.B MTBSF
+command (backward space over
+.I count
+file marks).
+.TP
+.B 3
+Issue a 
+.B MTFSR 
+command (forward space
+.I count
+inter-record gaps).
+.TP
+.B 4
+Issue a 
+.B MTBSR
+command (backward space
+.I count
+inter-record gaps).
+.TP
+.B 5
+Issue a 
+.B MTREW
+command (rewind).
+.TP
+.B 6
+Issue a 
+.B MTOFFL
+command (rewind and put the drive offline).
+.TP
+.B 7
+Issue a
+.B MTNOP
+command (no operation, set status only).
+.RE
+.TP
+.B i\fIoperation\fR\en\fIcount\fR\en
+Perform an extended
+.B MTIOCOP
+.BR ioctl (2)
+command using the specified parameters. The parameters are interpreted as the
+.B ASCII
+representations of the decimal values to place in the 
+.B mt_op
+and
+.B mt_count
+fields of the structure used in the
+.B ioctl
+call.  The return value is the
+.I count
+parameter when the operation is successful. The possible operations are:
+.RS
+.TP
+.B 0
+Issue a 
+.B MTCACHE
+command (switch cache on).
+.TP
+.B 1
+Issue a 
+.B MTNOCACHE
+command (switch cache off).
+.TP
+.B 2
+Issue a 
+.B MTRETEN
+command (retension the tape).
+.TP
+.B 3
+Issue a 
+.B MTERASE
+command (erase the entire tape).
+.TP
+.B 4
+Issue a 
+.B MTEOM
+command (position to end of media).
+.TP
+.B 5
+Issue a 
+.B MTNBSF
+command (backward space count files to BOF).
+.RE
+.TP
+.B S
+Return the status of the open device, as obtained with a
+.B MTIOCGET
+.B ioctl
+call.  If the operation was successful, an \*(lqack\*(rq is sent with the size
+of the status buffer, then the status buffer is sent (in binary, which is
+non-portable between different platforms).
+.TP
+.BI s sub-command
+This is a replacement for the previous 
+.B S 
+command, portable across different platforms. If the open device is a magnetic
+tape, return members of the magnetic tape status structure, as obtained with a
+.B MTIOCGET 
+ioctl call. If the open device is not a magnetic tape, an error is returned. If
+the 
+.B MTIOCGET
+operation was successful, the numerical value of the structure member is 
+returned in decimal. The following sub commands are supported:
+.RS
+.TP
+.B T
+return the content of the structure member
+.B mt_type
+which contains the type of the magnetic tape device.
+.TP
+.B D
+return the content of the structure member
+.B mt_dsreg
+which contains the "drive status register".
+.TP
+.B E
+return the content of the structure member
+.B mt_erreg
+which contains the "error register". This structure member must be retrieved
+first because it is cleared after each
+.B MTIOCGET
+ioctl call.
+.TP
+.B R
+return the content of the structure member
+.B mt_resid
+which contains the residual count of the last I/O.
+.TP
+.B F
+return the content of the structure member
+.B mt_fileno
+which contains the file number of the current tape position.
+.TP
+.B B
+return the content of the structure member
+.B mt_blkno
+which contains the block number of the current tape position.
+.TP
+.B f
+return the content of the structure member
+.B mt_flags
+which contains MTF_ flags from the driver.
+.TP
+.B b
+return the content of the structure member
+.B mt_bf
+which contains the optimum blocking factor.
+.RE
+.PP
+Any other command causes 
+.B rmt
+to exit.
+.SH DIAGNOSTICS
+All responses are of the form described above.
+.SH SEE ALSO
+.BR rcmd (3),
+.BR rexec (3),
+.I /usr/include/sys/mtio.h,
+.BR rdump (8),
+.BR rrestore (8)
+.SH BUGS
+People should be discouraged from using this for a remote file access protocol.
+.SH AUTHOR
+The
+.B dump/restore
+backup suit was ported to Linux's Second Extended File System by Remy Card
+<card@Linux.EU.Org>. He maintained the initial versions of 
+.B dump
+(up and including 0.4b4, released in january 1997).
+.PP
+Starting with 0.4b5, the new maintainer is Stelian Pop <stelian@popies.net>.
+.SH AVAILABILITY
+The
+.B dump/restore
+backup suit is available from <http://dump.sourceforge.net>
+.SH HISTORY
+The
+.B rmt
+command appeared in 4.2BSD.
diff --git a/rmt/rmt.c b/rmt/rmt.c
new file mode 100644 (file)
index 0000000..05874a3
--- /dev/null
+++ b/rmt/rmt.c
@@ -0,0 +1,615 @@
+/*
+ *     Ported to Linux's Second Extended File System as part of the
+ *     dump and restore backup suit
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+       "$Id: rmt.c,v 1.28 2003/11/22 16:52:16 stelian Exp $";
+#endif /* not linux */
+
+/*
+ * rmt
+ */
+#include <config.h>
+#include <compatlfs.h>
+#include <rmtflags.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/mtio.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifndef __linux__
+#include <sgtty.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int     tape = -1;
+
+static char    *record;
+static int     maxrecsize = -1;
+
+#define        SSIZE   64
+static char    device[SSIZE];
+static char    count[SSIZE], filemode[SSIZE], pos[SSIZE], op[SSIZE];
+
+static char    resp[BUFSIZ];
+
+static FILE    *debug;
+#define        DEBUG(f)        if (debug) fprintf(debug, f)
+#define        DEBUG1(f,a)     if (debug) fprintf(debug, f, a)
+#define        DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2)
+
+/*
+ * Support for Sun's extended RMT protocol
+ *     code originally written by Jörg Schilling <schilling@fokus.gmd.de>
+ *     and relicensed by his permission from GPL to BSD for use in dump.
+ *
+ *     rmt_version is 0 for regular clients (Linux included)
+ *     rmt_version is 1 for extended clients (Sun especially). In this case
+ *             we support some extended commands (see below) and we remap
+ *             the ioctl commands to the UNIX "standard", as per:
+ *                     ftp://ftp.fokus.gmd.de/pub/unix/star/README.mtio
+ *
+ *     In order to use rmt version 1, a client must send "I-1\n0\n" 
+ *     before issuing the other I commands.
+ */
+static int     rmt_version = 0;
+#define RMTI_VERSION   -1
+#define RMT_VERSION    1
+/* Extended 'i' commands */
+#define RMTI_CACHE     0
+#define RMTI_NOCACHE   1
+#define RMTI_RETEN     2
+#define RMTI_ERASE     3
+#define RMTI_EOM       4
+#define RMTI_NBSF      5
+/* Extended 's' comands */
+#define MTS_TYPE       'T'
+#define MTS_DSREG      'D'
+#define MTS_ERREG      'E'
+#define MTS_RESID      'R'
+#define MTS_FILENO     'F'
+#define MTS_BLKNO      'B'
+#define MTS_FLAGS      'f'
+#define MTS_BF         'b'
+
+static char    *checkbuf __P((char *, int));
+static void     error __P((int));
+static void     getstring __P((char *));
+static unsigned long swaplong __P((unsigned long inv));
+#ifdef ERMT
+char   *cipher __P((char *, int, int));
+void   decrypt __P((void));
+#endif
+
+int
+main(int argc, char *argv[])
+{
+       OFF_T rval = 0;
+       char c;
+       int n, i, cc, oflags;
+       unsigned long block = 0;
+       char *cp;
+
+       int magtape = 0;
+
+#ifdef ERMT
+       if (argc > 1 && strcmp(argv[1], "-d") == 0)
+               decrypt(); /* decrypt stdin to stdout, and exit() */
+#endif
+       /* Skip "-c /etc/rmt", which appears when rmt is used as a shell */
+       if (argc > 2 && strcmp(argv[1], "-c") == 0)
+               argc -= 2, argv += 2;
+       argc--, argv++;
+       if (argc > 0) {
+               debug = fopen(*argv, "w");
+               if (debug == 0)
+                       exit(1);
+               (void)setbuf(debug, (char *)0);
+       }
+top:
+       errno = 0;
+       rval = 0;
+       if (read(0, &c, 1) != 1)
+               exit(0);
+       switch (c) {
+
+       case 'O':
+               if (tape >= 0)
+                       (void) close(tape);
+               getstring(device);
+               getstring(filemode);
+               DEBUG2("rmtd: O %s %s\n", device, filemode);
+               /*
+                * Translate extended GNU syntax into its numeric platform equivalent
+                */
+               oflags = rmtflags_toint(filemode);
+#ifdef  O_TEXT
+               /*
+                * Default to O_BINARY the client may not know that we need it.
+                */
+               if ((oflags & O_TEXT) == 0)
+                       oflags |= O_BINARY;
+#endif
+               DEBUG2("rmtd: O %s %d\n", device, oflags);
+               /*
+                * XXX the rmt protocol does not provide a means to
+                * specify the permission bits; allow rw for everyone,
+                * as modified by the users umask
+                */
+               tape = OPEN(device, oflags, 0666);
+               if (tape < 0)
+                       goto ioerror;
+               block = 0;
+               {
+               struct mtget mt_stat;
+               magtape = ioctl(tape, MTIOCGET, (char *)&mt_stat) == 0;
+               }
+               goto respond;
+
+       case 'C':
+               DEBUG1("rmtd: C  (%lu blocks)\n", block);
+               getstring(device);              /* discard */
+               if (close(tape) < 0)
+                       goto ioerror;
+               tape = -1;
+               block = 0;
+               goto respond;
+
+#ifdef USE_QFA
+#define LSEEK_GET_TAPEPOS      10
+#define LSEEK_GO2_TAPEPOS      11
+#endif
+
+       case 'L':
+               getstring(count);
+               getstring(pos);
+               DEBUG2("rmtd: L %s %s\n", count, pos);
+               if (!magtape) { /* traditional */
+                       switch (atoi(pos)) {
+                       case SEEK_SET:
+                       case SEEK_CUR:
+                       case SEEK_END:
+                               rval = LSEEK(tape, (OFF_T)atoll(count), atoi(pos));
+                               break;
+#ifdef USE_QFA
+                       case LSEEK_GET_TAPEPOS:
+                               rval = LSEEK(tape, (OFF_T)0, SEEK_CUR);
+                               break;
+                       case LSEEK_GO2_TAPEPOS:
+                               rval = LSEEK(tape, (OFF_T)atoll(count), SEEK_SET);
+                               break;
+#endif /* USE_QFA */
+                       default:
+                               errno = EINVAL;
+                               goto ioerror;
+                               break;
+                       }
+               }
+               else {
+                       switch (atoi(pos)) {
+                       case SEEK_SET:
+                       case SEEK_CUR:
+                       case SEEK_END:
+                               rval = LSEEK(tape, (OFF_T)atoll(count), atoi(pos));
+                               break;
+#ifdef USE_QFA
+                       case LSEEK_GET_TAPEPOS: /* QFA */
+                       case LSEEK_GO2_TAPEPOS:
+                               {
+                               struct mtop buf;
+                               long mtpos;
+
+                               buf.mt_op = MTSETDRVBUFFER;
+                               buf.mt_count = MT_ST_BOOLEANS | MT_ST_SCSI2LOGICAL;
+                               if (ioctl(tape, MTIOCTOP, &buf) < 0) {
+                                       goto ioerror;
+                               }
+
+                               if (atoi(pos) == LSEEK_GET_TAPEPOS) { /* get tapepos */
+                                       if (ioctl(tape, MTIOCPOS, &mtpos) < 0) {
+                                               goto ioerror;
+                                       }
+                                       rval = (OFF_T)mtpos;
+                               } else {
+                                       buf.mt_op = MTSEEK;
+                                       buf.mt_count = atoi(count);
+                                       if (ioctl(tape, MTIOCTOP, &buf) < 0) {
+                                               goto ioerror;
+                                       }
+                                       rval = (OFF_T)buf.mt_count;
+                               }
+                               }
+                               break;
+#endif /* USE_QFA */
+                       default:
+                               errno = EINVAL;
+                               goto ioerror;
+                       }
+               }
+               if (rval < 0)
+                       goto ioerror;
+               goto respond;
+
+       case 'W':
+               getstring(count);
+               n = atoi(count);
+               if (n < 1)
+                       exit(2);
+               DEBUG2("rmtd: W %s (block = %lu)\n", count, block);
+               record = checkbuf(record, n);
+               for (i = 0; i < n; i += cc) {
+                       cc = read(0, &record[i], n - i);
+                       if (cc <= 0) {
+                               DEBUG("rmtd: premature eof\n");
+                               exit(2);
+                       }
+               }
+#ifdef ERMT
+               if ((cp = cipher(record, n, 1)) == NULL)
+                       goto ioerror;
+#else
+               cp = record;
+#endif
+               rval = write(tape, cp, n);
+               if (rval < 0)
+                       goto ioerror;
+               block += n >> 10;
+               goto respond;
+
+       case 'R':
+               getstring(count);
+               DEBUG2("rmtd: R %s (block %lu)\n", count, block);
+               n = atoi(count);
+               record = checkbuf(record, n);
+               rval = read(tape, record, n);
+               if (rval < 0)
+                       goto ioerror;
+#ifdef ERMT
+               if ((cp = cipher(record, rval, 0)) == NULL)
+                       goto ioerror;
+#else
+               cp = record;
+#endif
+               (void)sprintf(resp, "A%lld\n", (long long)rval);
+               (void)write(1, resp, strlen(resp));
+               (void)write(1, cp, rval);
+               block += n >> 10;
+               goto top;
+
+       case 'I':
+               getstring(op);
+               getstring(count);
+               DEBUG2("rmtd: I %s %s\n", op, count);
+               if (atoi(op) == RMTI_VERSION) {
+                       rval = RMT_VERSION;
+                       rmt_version = 1;
+               } 
+               else { 
+                       struct mtop mtop;
+                       mtop.mt_op = -1;
+                       if (rmt_version) {
+                               /* rmt version 1, assume UNIX/Solaris/Mac OS X client */
+                               switch (atoi(op)) {
+#ifdef  MTWEOF
+                                       case 0:
+                                               mtop.mt_op = MTWEOF;
+                                               break;
+#endif
+#ifdef  MTFSF
+                                       case 1:
+                                               mtop.mt_op = MTFSF;
+                                               break;
+#endif
+#ifdef  MTBSF
+                                       case 2:
+                                               mtop.mt_op = MTBSF;
+                                               break;
+#endif
+#ifdef  MTFSR
+                                       case 3:
+                                               mtop.mt_op = MTFSR;
+                                               break;
+#endif
+#ifdef  MTBSR
+                                       case 4:
+                                               mtop.mt_op = MTBSR;
+                                               break;
+#endif
+#ifdef  MTREW
+                                       case 5:
+                                               mtop.mt_op = MTREW;
+                                               break;
+#endif
+#ifdef  MTOFFL
+                                       case 6:
+                                               mtop.mt_op = MTOFFL;
+                                               break;
+#endif
+#ifdef  MTNOP
+                                       case 7:
+                                               mtop.mt_op = MTNOP;
+                                               break;
+#endif
+#ifdef  MTRETEN
+                    case 8:
+                        mtop.mt_op = MTRETEN;
+                        break;
+#endif
+#ifdef  MTERASE
+                    case 9:
+                        mtop.mt_op = MTERASE;
+                        break;
+#endif
+#ifdef  MTEOM
+                    case 10:
+                        mtop.mt_op = MTEOM;
+                        break;
+#endif
+                               }
+                               if (mtop.mt_op == -1) {
+                                       errno = EINVAL;
+                                       goto ioerror;
+                               }
+                       }
+                       else {
+                               /* rmt version 0, assume linux client */
+                               mtop.mt_op = atoi(op);
+                       }
+                       mtop.mt_count = atoi(count);
+                       if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0) {
+                               goto ioerror;
+                       }
+                       rval = mtop.mt_count;
+               }
+               goto respond;
+
+       case 'i':
+       {       struct mtop mtop;
+               getstring (op);
+               getstring (count);
+               DEBUG2 ("rmtd: i %s %s\n", op, count);
+               switch (atoi(op)) {
+#ifdef MTCACHE
+                       case RMTI_CACHE:
+                               mtop.mt_op = MTCACHE;
+                               break;
+#endif
+#ifdef MTNOCACHE
+                       case RMTI_NOCACHE:
+                               mtop.mt_op = MTNOCACHE;
+                               break;
+#endif
+#ifdef MTRETEN
+                       case RMTI_RETEN:
+                               mtop.mt_op = MTRETEN;
+                               break;
+#endif
+#ifdef MTERASE
+                       case RMTI_ERASE:
+                               mtop.mt_op = MTERASE;
+                               break;
+#endif
+#ifdef MTEOM
+                       case RMTI_EOM:
+                               mtop.mt_op = MTEOM;
+                               break;
+#endif
+#ifdef MTNBSF
+                       case RMTI_NBSF:
+                               mtop.mt_op = MTNBSF;
+                               break;
+#endif
+                       default:
+                               errno = EINVAL;
+                               goto ioerror;
+               }
+               mtop.mt_count = atoi (count);
+               if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0) {
+                       goto ioerror;
+               }
+
+               rval = mtop.mt_count;
+
+               goto respond;
+       }
+
+       case 'S':               /* status */
+               DEBUG("rmtd: S\n");
+               { struct mtget mtget;
+
+                 if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0) {
+                       goto ioerror;
+                 }
+
+                 if (rmt_version) {
+                       rval = sizeof(mtget);
+                       /* assume byte order:
+                       Linux on Intel (little), Solaris on SPARC (big), Mac OS X on PPC (big)
+                       thus need byte swapping from little to big
+                       */
+                       mtget.mt_type = swaplong(mtget.mt_type);
+                       mtget.mt_resid = swaplong(mtget.mt_resid);
+                       mtget.mt_dsreg = swaplong(mtget.mt_dsreg);
+                       mtget.mt_gstat = swaplong(mtget.mt_gstat);
+                       mtget.mt_erreg = swaplong(mtget.mt_erreg);
+                       mtget.mt_fileno = swaplong(mtget.mt_fileno);
+                       mtget.mt_blkno = swaplong(mtget.mt_blkno);
+                       (void)sprintf(resp, "A%lld\n", (long long)rval);
+                       (void)write(1, resp, strlen(resp));
+                       (void)write(1, (char *)&mtget, sizeof (mtget));
+                 } else {
+                       rval = sizeof (mtget);
+                       (void)sprintf(resp, "A%lld\n", (long long)rval);
+                       (void)write(1, resp, strlen(resp));
+                       (void)write(1, (char *)&mtget, sizeof (mtget));
+                 }
+                 goto top;
+               }
+
+       case 's':
+       {       char s;
+               struct mtget mtget;
+               DEBUG ("rmtd: s\n");
+
+               if (read (0, &s, 1) != 1)
+                       goto top;
+               DEBUG1 ("rmtd: s %d\n", s);
+               if (ioctl (tape, MTIOCGET, (char *) &mtget) < 0) {
+                       goto ioerror;
+               }
+
+               switch (s) {
+                       case MTS_TYPE:
+                               rval = mtget.mt_type;
+                               break;
+                       case MTS_DSREG:
+                               rval = mtget.mt_dsreg;
+                               break;
+                       case MTS_ERREG:
+                               rval = mtget.mt_erreg;
+                               break;
+                       case MTS_RESID:
+                               rval = mtget.mt_resid;
+                               break;
+                       case MTS_FILENO:
+                               rval = mtget.mt_fileno;
+                               break;
+                       case MTS_BLKNO:
+                               rval = mtget.mt_blkno;
+                               break;
+                       case MTS_FLAGS:
+                               rval = mtget.mt_gstat;
+                               break;
+                       case MTS_BF:
+                               rval = 0;
+                               break;
+                       default:
+                               errno = EINVAL;
+                               goto ioerror;
+               }
+
+               goto respond;
+       }
+
+       case 'V':       /* version */
+               getstring(op);
+               DEBUG1("rmtd: V %s\n", op);
+               rval = 2;
+               goto respond;
+
+       default:
+               DEBUG1("rmtd: garbage command %c\n", c);
+               exit(3);
+       }
+respond:
+       DEBUG1("rmtd: A %lld\n", (long long)rval);
+       (void)sprintf(resp, "A%lld\n", (long long)rval);
+       (void)write(1, resp, strlen(resp));
+       goto top;
+ioerror:
+       error(errno);
+       goto top;
+}
+
+static void getstring(char *bp)
+{
+       int i;
+       char *cp = bp;
+
+       for (i = 0; i < SSIZE - 1; i++) {
+               if (read(0, cp+i, 1) != 1)
+                       exit(0);
+               if (cp[i] == '\n')
+                       break;
+       }
+       cp[i] = '\0';
+}
+
+static char *
+checkbuf(char *record, int size)
+{
+
+       if (size <= maxrecsize)
+               return (record);
+       if (record != 0)
+               free(record);
+       record = malloc(size);
+       if (record == 0) {
+               DEBUG("rmtd: cannot allocate buffer space\n");
+               exit(4);
+       }
+       maxrecsize = size;
+       while (size > 1024 &&
+              setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
+               size -= 1024;
+       return (record);
+}
+
+static void
+error(int num)
+{
+
+       DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
+       (void)snprintf(resp, sizeof(resp), "E%d\n%s\n", num, strerror(num));
+       (void)write(1, resp, strlen(resp));
+}
+
+static unsigned long
+swaplong(unsigned long inv)
+{
+        union lconv {
+               unsigned long   ul;
+               unsigned char   uc[4];
+       } *inp, outv;
+
+       inp = (union lconv *)&inv;
+
+       outv.uc[0] = inp->uc[3];
+       outv.uc[1] = inp->uc[2];
+       outv.uc[2] = inp->uc[1];
+       outv.uc[3] = inp->uc[0];
+
+       return (outv.ul);
+}