From 6ca85a1b3c0486912b19bd5e47f78e9207ba5298 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Mon, 19 May 2008 23:04:23 -0600 Subject: [PATCH] Imported Upstream version 0.4b37 --- CHANGES | 1380 ++++ COPYRIGHT | 36 + INSTALL | 17 + KNOWNBUGS | 17 + MAINTAINERS | 15 + MCONFIG.in | 99 + Makefile.in | 24 + README | 10 + REPORTING-BUGS | 57 + THANKS | 134 + TODO | 37 + common/Makefile.in | 33 + common/dumprmt.c | 513 ++ compat/include/Makefile.in | 24 + compat/include/bsdcompat.h | 292 + compat/include/bylabel.h | 41 + compat/include/compaterr.h | 88 + compat/include/compatglob.h | 100 + compat/include/compatlfs.h | 68 + compat/include/darwin.h | 133 + compat/include/lzoconf.h | 451 ++ compat/include/minilzo.h | 100 + compat/include/pathnames.h | 57 + compat/include/protocols/dumprestore.h | 175 + compat/include/rmtflags.h | 46 + compat/include/system.h | 45 + compat/lib/Makefile.in | 37 + compat/lib/README.LZO | 133 + compat/lib/README2.LZO | 10 + compat/lib/bylabel.c | 261 + compat/lib/compaterr.c | 223 + compat/lib/compatglob.c | 831 +++ compat/lib/minilzo.c | 2935 ++++++++ compat/lib/rmtflags.c | 188 + compat/lib/system.c | 94 + config.guess | 1354 ++++ config.h.in | 129 + config.sub | 1460 ++++ configure | 6638 +++++++++++++++++ configure.in | 576 ++ depfix.sed | 34 + dump.lsm | 18 + dump.spec | 300 + dump/Makefile.in | 55 + dump/dump.8.in | 660 ++ dump/dump.h | 289 + dump/itime.c | 328 + dump/main.c | 1399 ++++ dump/optr.c | 736 ++ dump/tape.c | 1495 ++++ dump/traverse.c | 1399 ++++ dump/unctime.c | 130 + examples/cron_dump_to_disk/README | 31 + examples/cron_dump_to_disk/backup | 179 + examples/cron_dump_to_disk/backup_rotate | 90 + examples/cron_dump_to_disk/backupskel.tar.gz | Bin 0 -> 297 bytes .../cron_dump_to_disk/crontab_entries.txt | 4 + examples/dump_on_cd/README | 53 + examples/dump_on_cd/dump_userinfo.sh | 12 + examples/dump_on_cd/start_dump.sh | 24 + examples/dump_on_cd/verify_dump.sh | 8 + examples/dump_on_cd_2/DE/backup_CD | 37 + examples/dump_on_cd_2/DE/backup_DVD | 44 + examples/dump_on_cd_2/DE/dump_userexit_CD | 24 + examples/dump_on_cd_2/DE/dump_userexit_DVD | 25 + examples/dump_on_cd_2/EN/backup_CD | 36 + examples/dump_on_cd_2/EN/backup_DVD | 44 + examples/dump_on_cd_2/EN/dump_userexit_CD | 23 + examples/dump_on_cd_2/EN/dump_userexit_DVD | 25 + examples/dump_on_cd_2/README | 12 + examples/dump_on_remote_cd/README | 35 + examples/dump_on_remote_cd/dump-to-remote-cd | 98 + .../get-dumpdata-to-cdrecord | 60 + examples/encrypted_rmt/README | 77 + examples/howto/ultra-mini-howto | 314 + examples/remote_backup_ssh/backitup | 59 + install-sh | 251 + linux-1.2.x.patch | 17 + restore/Makefile.in | 55 + restore/dirs.c | 817 ++ restore/extern.h | 156 + restore/interactive.c | 1042 +++ restore/main.c | 789 ++ restore/restore.8.in | 757 ++ restore/restore.c | 1209 +++ restore/restore.h | 196 + restore/symtab.c | 639 ++ restore/tape.c | 3122 ++++++++ restore/utilities.c | 720 ++ rmt/Makefile.in | 53 + rmt/cipher.c | 131 + rmt/rmt.8.in | 365 + rmt/rmt.c | 615 ++ 93 files changed, 37952 insertions(+) create mode 100644 CHANGES create mode 100644 COPYRIGHT create mode 100644 INSTALL create mode 100644 KNOWNBUGS create mode 100644 MAINTAINERS create mode 100644 MCONFIG.in create mode 100644 Makefile.in create mode 100644 README create mode 100644 REPORTING-BUGS create mode 100644 THANKS create mode 100644 TODO create mode 100644 common/Makefile.in create mode 100644 common/dumprmt.c create mode 100644 compat/include/Makefile.in create mode 100644 compat/include/bsdcompat.h create mode 100644 compat/include/bylabel.h create mode 100644 compat/include/compaterr.h create mode 100644 compat/include/compatglob.h create mode 100644 compat/include/compatlfs.h create mode 100644 compat/include/darwin.h create mode 100644 compat/include/lzoconf.h create mode 100644 compat/include/minilzo.h create mode 100644 compat/include/pathnames.h create mode 100644 compat/include/protocols/dumprestore.h create mode 100644 compat/include/rmtflags.h create mode 100644 compat/include/system.h create mode 100644 compat/lib/Makefile.in create mode 100644 compat/lib/README.LZO create mode 100644 compat/lib/README2.LZO create mode 100644 compat/lib/bylabel.c create mode 100644 compat/lib/compaterr.c create mode 100644 compat/lib/compatglob.c create mode 100644 compat/lib/minilzo.c create mode 100644 compat/lib/rmtflags.c create mode 100644 compat/lib/system.c create mode 100755 config.guess create mode 100644 config.h.in create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100644 depfix.sed create mode 100644 dump.lsm create mode 100644 dump.spec create mode 100644 dump/Makefile.in create mode 100644 dump/dump.8.in create mode 100644 dump/dump.h create mode 100644 dump/itime.c create mode 100644 dump/main.c create mode 100644 dump/optr.c create mode 100644 dump/tape.c create mode 100644 dump/traverse.c create mode 100644 dump/unctime.c create mode 100644 examples/cron_dump_to_disk/README create mode 100755 examples/cron_dump_to_disk/backup create mode 100755 examples/cron_dump_to_disk/backup_rotate create mode 100644 examples/cron_dump_to_disk/backupskel.tar.gz create mode 100644 examples/cron_dump_to_disk/crontab_entries.txt create mode 100644 examples/dump_on_cd/README create mode 100755 examples/dump_on_cd/dump_userinfo.sh create mode 100755 examples/dump_on_cd/start_dump.sh create mode 100755 examples/dump_on_cd/verify_dump.sh create mode 100644 examples/dump_on_cd_2/DE/backup_CD create mode 100644 examples/dump_on_cd_2/DE/backup_DVD create mode 100644 examples/dump_on_cd_2/DE/dump_userexit_CD create mode 100644 examples/dump_on_cd_2/DE/dump_userexit_DVD create mode 100644 examples/dump_on_cd_2/EN/backup_CD create mode 100644 examples/dump_on_cd_2/EN/backup_DVD create mode 100644 examples/dump_on_cd_2/EN/dump_userexit_CD create mode 100644 examples/dump_on_cd_2/EN/dump_userexit_DVD create mode 100644 examples/dump_on_cd_2/README create mode 100644 examples/dump_on_remote_cd/README create mode 100755 examples/dump_on_remote_cd/dump-to-remote-cd create mode 100755 examples/dump_on_remote_cd/get-dumpdata-to-cdrecord create mode 100644 examples/encrypted_rmt/README create mode 100644 examples/howto/ultra-mini-howto create mode 100644 examples/remote_backup_ssh/backitup create mode 100755 install-sh create mode 100644 linux-1.2.x.patch create mode 100644 restore/Makefile.in create mode 100644 restore/dirs.c create mode 100644 restore/extern.h create mode 100644 restore/interactive.c create mode 100644 restore/main.c create mode 100644 restore/restore.8.in create mode 100644 restore/restore.c create mode 100644 restore/restore.h create mode 100644 restore/symtab.c create mode 100644 restore/tape.c create mode 100644 restore/utilities.c create mode 100644 rmt/Makefile.in create mode 100644 rmt/cipher.c create mode 100644 rmt/rmt.8.in create mode 100644 rmt/rmt.c diff --git a/CHANGES b/CHANGES new file mode 100644 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 for the suggestion. + +2. Fix compilation on (at least the Linux Debian port to) AMD64. + ( defines some types (__s64 and __u64) + that are also defined by () 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 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 + 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 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 + 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 . + +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 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 for reporting this, + debugging the issue and making the patch. + +10. Made restore understand FreeBSD UFS2 tapes. Thanks to + David 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 + 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 + for the patch. + +2. Fixed configure to correctly understand CPPFLAGS, CFLAGS, + LDFLAGS environment variables. Thanks to Arcady Genkin + 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 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 + for reporting this bug. + +5. Made restore build on Solaris, making possible to + restore Linux's "enhanced" tapes. Thanks to Uwe Gohlke + for the patch. + +6. Made an extension in the dump tape format capable of saving + MacOSX specific inode extensions. Uwe Gohlke + 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 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 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 + 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 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 + for reporting the bug. + +5. Fixed (again) handling of long (largefile) seeks in rmt. + Thanks to Fabrice Bellet 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 + for reporting the bug. + +7. Fixed a bug preventing dump to access a filesystem having + a label exactly 16 bytes in length. Thanks to + 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 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 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 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 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 for the patch. + +13. Fixed the 'S' command handling in the rmt client part. + Thanks to Philippe Troin 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 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 + for the patch and to + Markus Oberhumer 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 + 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 + for the patch. + +19. Made dump work with 2.5 kernel end of tape early warning semantics. + Thanks to Kai Makisara 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 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 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 + 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 , Elliott Mitchell + , Greg Edwards , + Brian Hoy . (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 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 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 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 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 + 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 + 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 + 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 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 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 + 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 . + +3. Fixed the tape length calculation when using large tapes + and compression. Thanks to Georg Lippold + 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 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 for + reporting the bug. + +6. Fixed a lot of warnings in the code shown when compiling + with 'gcc -W'. Thanks to Matthias Andree + for reporting this. + +7. Fixed a small markup bug in the dump man page. Thanks to + Eric S. Raymond 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 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 + 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 in the FreeBSD version + of dump: http://www.FreeBSD.org/cgi/query-pr.cgi?pr=32414 + Thanks to Ted Grzesik for reporting the bug and + help testing the patch. + +4. Added some example scripts from Gerd Bavendiek + 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 + and Peter Samuel . + +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 . + +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 + +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 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 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 + for reporting the bug. + +6. Added the appropriate error message when dump fails to + open the output file for writing. Thanks to Amith Varghese + 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 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 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 + for reporting this bug. + +9. Added the -P option to restore to create a + Quick File Access file from an already made dump. Patch + contributed by Uwe Gohlke . + +10. Made restore compile and run on Solaris, making it a + possible replacement for the standard ufsrestore. Port was + contributed by Uwe Gohlke . + +Changes between versions 0.4b25 and 0.4b26 (released January 7, 2002) +===================================================================== + +1. Added a set of backup scripts from Eugenio Diaz + 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 + for reporting the bug. + +3. Fixed several restore bugs occuring when trying to + restore some missing files on the tape. Thanks to Chris + Siebenmann for reporting the bug. + +4. Fixed --with-ldopts configure argument passing, installing from + a separate object directory, makefile cleanups contributed + by . + +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 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 for reporting the bugs. + +3. Added a script from David B. Peterson + to the examples section. It features dumping several + filesystems to a remote tape drive upon ssh. + +4. Added a patch provided by Richard Jones + 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 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 + 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 and to Theodore T'so + 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 + 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 . + +3. Check for the e2fsprogs header instead of + the linux kernel header. This ensures that dump always has the + latest version of this file. Patch submitted by + Andreas Dilger . + +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 . + +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 + . 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 + , 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 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 for reporting the + bug and providing a patch. + +3. Added a compression option to dump, contributed by Jerry + Peters . + + 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 for + the patch and to Bdale Garbee 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 . + +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 . 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 + 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 + 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 + 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 and + bgjenero for reporting the bug. + +5. Added the throughput information in dump's progression + messages. Thanks to Andreas Dilger + 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 + 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 for submitting the patch, + and to Theodore T'so 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 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 + for reporting the bug and to + Dave Platt 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 + 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 + 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 + 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 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 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 + 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 + 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 + 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 + 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 + 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 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 + 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 for reporting + the bug. + +2. Fixed a readline-related bug which prevented + 'cat DUMPFILE | restore -i -f -' from working. Thanks + to Charles Karney + 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 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 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 + 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 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 + 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 + 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 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 + 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 + 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 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 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 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 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 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 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 + 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 + 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 + for reporting the bug. + +2. Removed the requirement to build the RPM as root from the + spec file. Thanks to Christian Weisgerber + 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 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 + 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 + for submitting the patch. + +2. Fix for the exit code when using the size estimate option of + dump. Thanks to Matti Taskinen 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 + 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 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 + 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 + 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 + 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 + . + +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 001, 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 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 + 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 + for reporting the bug and to + Theodore Y. Ts'o 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 + 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 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 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 + 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 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 ). + +4. Made possible to dump a file system not mentioned in /etc/fstab. + (Debian bug #11904, patch provided by Eirik Fuller ). + +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 ). + +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 + +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 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 , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 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 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 index 0000000..b66b3e6 --- /dev/null +++ b/MAINTAINERS @@ -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 + +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 . + diff --git a/MCONFIG.in b/MCONFIG.in new file mode 100644 index 0000000..e20399e --- /dev/null +++ b/MCONFIG.in @@ -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 index 0000000..2dbd90a --- /dev/null +++ b/Makefile.in @@ -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 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 index 0000000..479ae42 --- /dev/null +++ b/REPORTING-BUGS @@ -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 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 , by using +the Ext2fs library, written by Theodore Ts'o . + +Kevin Layer added the comparison code in restore. + +Doug Paul helped me to make dump able to backup 2GB+ +filesystems. + +David Frey (the old Debian dump maintainer), +Bdale Garbee (the new Debian dump maintainer) and the people +from Red Hat Software provided lots of patches. + +Stelian Pop 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 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 + . + +7. Better readline completition in restore (escape spaces etc). diff --git a/common/Makefile.in b/common/Makefile.in new file mode 100644 index 0000000..80ea04d --- /dev/null +++ b/common/Makefile.in @@ -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 index 0000000..7f88f63 --- /dev/null +++ b/common/dumprmt.c @@ -0,0 +1,513 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#include +#elif defined sunos +#include + +#include +#else +#include +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef __STDC__ +#include +#include +#include +#endif + +#ifdef __linux__ +#include +#endif + +#include +#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 index 0000000..6fbfe48 --- /dev/null +++ b/compat/include/Makefile.in @@ -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 index 0000000..4b9b907 --- /dev/null +++ b/compat/include/bsdcompat.h @@ -0,0 +1,292 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 2000-2002 + * + * $Id: bsdcompat.h,v 1.23 2004/07/01 09:14:48 stelian Exp $ + */ + +#include +#include +#include +#include + +#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 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 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 index 0000000..baa334a --- /dev/null +++ b/compat/include/bylabel.h @@ -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 + * - added Native Language Support + * 2000-01-20 James Antill + * - Added error message if /proc/partitions cannot be opened + * 2000-05-09 Erik Troan + * - Added cache for UUID and disk labels + * Wed Aug 16 2000 Erik Troan + * - Ported to dump/restore + * Stelian Pop - Alcôve , 2000-2002 + * + * $Id: bylabel.h,v 1.6 2004/07/05 15:02:36 stelian Exp $ + */ + +#ifndef _BYLABEL_H_ +#define _BYLABEL_H_ + +#include + +#ifdef HAVE_BLKID + +#include + +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 index 0000000..14e6671 --- /dev/null +++ b/compat/include/compaterr.h @@ -0,0 +1,88 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 + +#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 +#endif + +#include + +#include + +#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 index 0000000..df2a536 --- /dev/null +++ b/compat/include/compatglob.h @@ -0,0 +1,100 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 + +#ifdef HAVE_GLOB +#include +#else + +#include + +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 index 0000000..fe7db5f --- /dev/null +++ b/compat/include/compatlfs.h @@ -0,0 +1,68 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Stelian Pop - Alcôve , 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 + +#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 index 0000000..bcab1ab --- /dev/null +++ b/compat/include/darwin.h @@ -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 index 0000000..96db180 --- /dev/null +++ b/compat/include/lzoconf.h @@ -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 + + 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 +#endif +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/*********************************************************************** +// LZO requires a conforming +************************************************************************/ + +#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 +# 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 index 0000000..e3270f9 --- /dev/null +++ b/compat/include/minilzo.h @@ -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 + + 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 index 0000000..281d204 --- /dev/null +++ b/compat/include/pathnames.h @@ -0,0 +1,57 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include + +#ifdef __linux__ +#include /* 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 index 0000000..fc43715 --- /dev/null +++ b/compat/include/protocols/dumprestore.h @@ -0,0 +1,175 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 + +/* + * 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 index 0000000..a1c49fb --- /dev/null +++ b/compat/include/rmtflags.h @@ -0,0 +1,46 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 index 0000000..5ed2d27 --- /dev/null +++ b/compat/include/system.h @@ -0,0 +1,45 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 index 0000000..cc90969 --- /dev/null +++ b/compat/lib/Makefile.in @@ -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 index 0000000..fd1ea8a --- /dev/null +++ b/compat/lib/README.LZO @@ -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 + + 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 index 0000000..b27597c --- /dev/null +++ b/compat/lib/README2.LZO @@ -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, , http://www.oberhumer.com/ diff --git a/compat/lib/bylabel.c b/compat/lib/bylabel.c new file mode 100644 index 0000000..5a40a70 --- /dev/null +++ b/compat/lib/bylabel.c @@ -0,0 +1,261 @@ +/* + * mount_by_label.c - aeb + * + * 1999-02-22 Arkadiusz Mi¶kiewicz + * - added Native Language Support + * 2000-01-20 James Antill + * - Added error message if /proc/partitions cannot be opened + * 2000-05-09 Erik Troan + * - Added cache for UUID and disk labels + * Wed Aug 16 2000 Erik Troan + * - Ported to dump/restore + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000..8ae4686 --- /dev/null +++ b/compat/lib/compaterr.c @@ -0,0 +1,223 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include +#include +#include + +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 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 index 0000000..8cf77ea --- /dev/null +++ b/compat/lib/compatglob.c @@ -0,0 +1,831 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include + +#ifndef HAVE_GLOB + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000..85771eb --- /dev/null +++ b/compat/lib/minilzo.c @@ -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 + + 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 +#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 +#endif +#include + +#ifndef __LZO_CONF_H +#define __LZO_CONF_H + +#if !defined(__LZO_IN_MINILZO) +# ifndef __LZOCONF_H +# include +# endif +#endif + +#if defined(__BOUNDS_CHECKING_ON) +# include +#else +# define BOUNDS_CHECKING_OFF_DURING(stmt) stmt +# define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr) +#endif + +#if !defined(LZO_HAVE_CONFIG_H) +# include +# include +# if !defined(NO_STDLIB_H) +# include +# endif +# define HAVE_MEMCMP +# define HAVE_MEMCPY +# define HAVE_MEMMOVE +# define HAVE_MEMSET +#else +# include +# if defined(HAVE_STDDEF_H) +# include +# endif +# if defined(STDC_HEADERS) +# include +# include +# 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 +# endif +#endif +#include + +#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 +# if 1 && defined(__WATCOMC__) +# include + __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" + "\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 +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 +#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 index 0000000..5181f1c --- /dev/null +++ b/compat/lib/rmtflags.c @@ -0,0 +1,188 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include +#include + +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 index 0000000..b3b7932 --- /dev/null +++ b/compat/lib/system.c @@ -0,0 +1,94 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000..fd30ab0 --- /dev/null +++ b/config.guess @@ -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 . +# Please send patches to . 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 ." + +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 <$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 /* 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 + + 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 + #include + + 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 + 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 + #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 + #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' /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 + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # 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 < +# include +#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 + 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 +# 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 < 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 index 0000000..799b2f0 --- /dev/null +++ b/config.h.in @@ -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 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 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 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 header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the 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 does not define. */ +#undef quad_t + +/* Define to `uint64_t' if does not define. */ +#undef u_quad_t diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..9ff085e --- /dev/null +++ b/config.sub @@ -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 . 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 ." + +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 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 +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#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 if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + 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 &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &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 +#include +#include +#include +/* 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 +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 to if __STDC__ is defined, since + # 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 +#else +# include +#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 +_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 to if __STDC__ is defined, since + # 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 +#else +# include +#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 +_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 +#include +#include +#include + +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 + +_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 + +_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 +#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 +_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 +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +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 +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +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 +_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 +_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 +_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 +_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 declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#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 declares glob. + For example, HP-UX 11i declares gettimeofday. */ +#define glob innocuous_glob + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char glob (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#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 +# 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 +_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 +_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 ." +_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 <>$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 <>$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 index 0000000..bcafc46 --- /dev/null +++ b/configure.in @@ -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 +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include ], +[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 +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include ], +[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 +# 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 index 0000000..4ed209a --- /dev/null +++ b/depfix.sed @@ -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 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 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 +- dump 0.4b37 released, first packaging. + +* Wed Apr 21 2004 Stelian Pop +- dump 0.4b36 released, first packaging. + +* Sun Dec 21 2003 Stelian Pop +- dump 0.4b35 released, first packaging. + +* Fri Apr 18 2003 Stelian Pop +- dump 0.4b34 released, first packaging. + +* Mon Feb 10 2003 Stelian Pop +- dump 0.4b33 released, first packaging. + +* Fri Nov 15 2002 Stelian Pop +- dump 0.4b32 released, first packaging. + +* Tue Jul 30 2002 Stelian Pop +- dump 0.4b31 released, first packaging. + +* Thu Jul 25 2002 Stelian Pop +- dump 0.4b30 released, first packaging. + +* Sat Jun 8 2002 Stelian Pop +- dump 0.4b29 released, first packaging. + +* Fri Apr 12 2002 Stelian Pop +- dump 0.4b28 released, first packaging. + +* Fri Feb 15 2002 Stelian Pop +- dump 0.4b27 released, first packaging. + +* Mon Jan 7 2002 Stelian Pop +- dump 0.4b26 released, first packaging. + +* Sat Nov 17 2001 Stelian Pop +- dump 0.4b25 released, first packaging. + +* Wed Sep 12 2001 Stelian Pop +- dump 0.4b24 released, first packaging. + +* Fri Jul 20 2001 Stelian Pop +- dump 0.4b23 released, first packaging. + +* Sat May 12 2001 Stelian Pop +- dump 0.4b22 released, first packaging. + +* Sat Jan 30 2001 Stelian Pop +- dump 0.4b21 released, first packaging. + +* Fri Nov 10 2000 Stelian Pop +- dump 0.4b20 released, first packaging. + +* Sun Aug 20 2000 Stelian Pop +- dump 0.4b19 released, first packaging. + +* Thu Jun 30 2000 Stelian Pop +- dump 0.4b18 released, first packaging. + +* Thu Jun 1 2000 Stelian Pop +- dump 0.4b17 released, first packaging. + +* Sat Mar 11 2000 Stelian Pop +- dump 0.4b16 released, first packaging. + +* Thu Mar 2 2000 Stelian Pop +- dump 0.4b15 released, first packaging. + +* Thu Feb 10 2000 Stelian Pop +- dump 0.4b14 released, first packaging. + +* Fri Jan 21 2000 Stelian Pop +- dump 0.4b13 released, first packaging. + +* Fri Jan 8 2000 Stelian Pop +- dump 0.4b12 released, first packaging. + +* Sun Dec 5 1999 Stelian Pop +- dump 0.4b11 released, first packaging. + +* Sun Nov 21 1999 Stelian Pop +- dump 0.4b10 released, first packaging. + +* Thu Nov 11 1999 Stelian Pop +- make static versions also for rescue purposes. + +* Wed Nov 5 1999 Stelian Pop +- dump 0.4b9 released, first packaging. + +* Wed Nov 3 1999 Stelian Pop +- dump 0.4b8 released, first packaging. + +* Thu Oct 8 1999 Stelian Pop +- dump 0.4b7 released, first packaging. + +* Thu Sep 30 1999 Stelian Pop +- dump 0.4b6 released, first packaging. + +* Fri Sep 10 1999 Jeff Johnson +- recompile with e2fsprogs = 1.15 (#4962). + +* Sat Jul 31 1999 Jeff Johnson +- 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 +- remove setuid/setgid bits from /sbin/rmt (dump/restore are OK). + +* Sun Mar 21 1999 Cristian Gafton +- auto rebuild in the new build environment (release 6) + +* Fri Mar 19 1999 Jeff Johnson +- strip binaries. + +* Thu Mar 18 1999 Jeff Johnson +- Fix dangling symlinks (#1551). + +* Wed Mar 17 1999 Michael Maher +- Top O' the morning, build root's fixed for man pages. + +* Fri Feb 19 1999 Preston Brown +- upgraded to dump 0.4b4, massaged patches. + +* Tue Feb 02 1999 Ian A Cameron +- added patch from Derrick J Brashear for traverse.c to stop bread errors + +* Wed Jan 20 1999 Jeff Johnson +- restore original 6755 root.tty to dump/restore, defattr did tty->root (#684). +- mark /etc/dumpdates as noreplace. + +* Tue Jul 14 1998 Jeff Johnson +- add build root. + +* Tue May 05 1998 Prospector System +- translations modified for de, fr, tr + +* Thu Apr 30 1998 Cristian Gafton +- added a patch for resolving linux/types.h and sys/types.h conflicts + +* Wed Dec 31 1997 Erik Troan +- added prototype of llseek() so dump would work on large partitions + +* Thu Oct 30 1997 Donnie Barnes +- made all symlinks relative instead of absolute + +* Thu Jul 10 1997 Erik Troan +- built against glibc + +* Thu Mar 06 1997 Michael K. Johnson +- Moved rmt to its own package. + +* Tue Feb 11 1997 Michael Fulbright +- Added endian cleanups for SPARC + +* Fri Feb 07 1997 Michael K. Johnson +- Made /etc/dumpdates writeable by group disk. diff --git a/dump/Makefile.in b/dump/Makefile.in new file mode 100644 index 0000000..f18c01e --- /dev/null +++ b/dump/Makefile.in @@ -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 index 0000000..487302d --- /dev/null +++ b/dump/dump.8.in @@ -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 001, 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 +. 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 . +.SH AVAILABILITY +The +.B dump/restore +backup suite is available from +.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 index 0000000..fafd4c3 --- /dev/null +++ b/dump/dump.h @@ -0,0 +1,289 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include + +#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 +#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 + +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 +#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 index 0000000..f2cc763 --- /dev/null +++ b/dump/itime.c @@ -0,0 +1,328 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#ifdef __STDC__ +#include +#include +#endif + +#include +#include +#include +#ifdef __linux__ +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#include +#include +#include +#elif defined sunos +#include + +#include +#include +#include +#else +#include +#endif + +#include + +#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 index 0000000..b73a788 --- /dev/null +++ b/dump/main.c @@ -0,0 +1,1399 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef __linux__ +#include +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#include +#include +#include /* for definition of BLKFLSBUF */ +#elif defined sunos +#include + +#include +#include +#else +#include +#include +#endif + +#include + +#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 index 0000000..a4504da --- /dev/null +++ b/dump/optr.c @@ -0,0 +1,736 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#include +#include +#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 index 0000000..2df4d1e --- /dev/null +++ b/dump/tape.c @@ -0,0 +1,1495 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __STDC__ +#include +#include +#include +#else +int write(), read(); +#endif + +#ifdef __linux__ +#include +#include +#include +#include /* for definition of BLKFLSBUF */ +#ifndef BLKFLSBUF /* last resort... */ +#define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache. */ +#endif +#include +#endif +#include +#include +#include +#include +#ifdef __linux__ +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#include +#include +#elif defined sunos +#include + +#include +#include +#else +#include +#include +#endif /* __linux__ */ + +#include + +#ifdef HAVE_ZLIB +#include +#endif /* HAVE_ZLIB */ + +#ifdef HAVE_BZLIB +#include +#endif /* HAVE_BZLIB */ + +#ifdef HAVE_LZO +#include +#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 index 0000000..4104799 --- /dev/null +++ b/dump/traverse.c @@ -0,0 +1,1399 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#ifdef __STDC__ +#include +#include +#endif +#include + +#include +#include +#ifdef __linux__ +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#include +#include +#include +#elif defined sunos +#include + +#include +#include +#include +#else +#include +#include +#include +#endif /* __linux__ */ + +#include + +#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 index 0000000..684719d --- /dev/null +++ b/dump/unctime.c @@ -0,0 +1,130 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#ifdef __STDC__ +#include +#include +#endif + +#include +#include + +#ifdef __linux__ +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#include +#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 index 0000000..5301f17 --- /dev/null +++ b/examples/cron_dump_to_disk/README @@ -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 index 0000000..da6bda6 --- /dev/null +++ b/examples/cron_dump_to_disk/backup @@ -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 index 0000000..2e8eeb9 --- /dev/null +++ b/examples/cron_dump_to_disk/backup_rotate @@ -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 index 0000000000000000000000000000000000000000..68614a9d63325035d3117b21cec65b31311d55cb GIT binary patch literal 297 zcmV+^0oMK>iwFQhOZ7Vd1MSwqYQ!KE1yDaFU!YH)Pye91u3G3i%mk*;Cg8+H|Gvhd zn=YmkigpV3Y!ZlzgzJ4#8`T_NfwN?oE_n^%or!>tizm2RbjgGhVpJ`h!WYyp< zTeIPtDdcaS@_qE5nYZ*g)c%Kn{`a8GbDqv^H^8p>AL{&PkNMw4>HoOq)N}*v%HQ#p zzgR~8J!tbX9p|6$J&1vk$(@`JfzpVIRAa+PxbuA vnEzd9^S;dM>Fw{&e`V$eFGRBC?=AWd00000000000PriHH18vd04M+e*G`~J literal 0 HcmV?d00001 diff --git a/examples/cron_dump_to_disk/crontab_entries.txt b/examples/cron_dump_to_disk/crontab_entries.txt new file mode 100644 index 0000000..f7ca35e --- /dev/null +++ b/examples/cron_dump_to_disk/crontab_entries.txt @@ -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 index 0000000..ae04ce5 --- /dev/null +++ b/examples/dump_on_cd/README @@ -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 index 0000000..9096048 --- /dev/null +++ b/examples/dump_on_cd/dump_userinfo.sh @@ -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 index 0000000..df98c0a --- /dev/null +++ b/examples/dump_on_cd/start_dump.sh @@ -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 index 0000000..2b19702 --- /dev/null +++ b/examples/dump_on_cd/verify_dump.sh @@ -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 index 0000000..06f7c97 --- /dev/null +++ b/examples/dump_on_cd_2/DE/backup_CD @@ -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 index 0000000..fbee957 --- /dev/null +++ b/examples/dump_on_cd_2/DE/backup_DVD @@ -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 index 0000000..a8f8db8 --- /dev/null +++ b/examples/dump_on_cd_2/DE/dump_userexit_CD @@ -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 index 0000000..bdfe22a --- /dev/null +++ b/examples/dump_on_cd_2/DE/dump_userexit_DVD @@ -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 index 0000000..94ae81d --- /dev/null +++ b/examples/dump_on_cd_2/EN/backup_CD @@ -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 index 0000000..518e95b --- /dev/null +++ b/examples/dump_on_cd_2/EN/backup_DVD @@ -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 index 0000000..cb45989 --- /dev/null +++ b/examples/dump_on_cd_2/EN/dump_userexit_CD @@ -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 index 0000000..e5fcef4 --- /dev/null +++ b/examples/dump_on_cd_2/EN/dump_userexit_DVD @@ -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 index 0000000..d4ed661 --- /dev/null +++ b/examples/dump_on_cd_2/README @@ -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 diff --git a/examples/dump_on_remote_cd/README b/examples/dump_on_remote_cd/README new file mode 100644 index 0000000..d07761d --- /dev/null +++ b/examples/dump_on_remote_cd/README @@ -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 ] [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 index 0000000..cefc321 --- /dev/null +++ b/examples/dump_on_remote_cd/dump-to-remote-cd @@ -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 ] [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 ] [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 index 0000000..ef7f226 --- /dev/null +++ b/examples/dump_on_remote_cd/get-dumpdata-to-cdrecord @@ -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 -f " + 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 index 0000000..12a95f5 --- /dev/null +++ b/examples/encrypted_rmt/README @@ -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 diff --git a/examples/howto/ultra-mini-howto b/examples/howto/ultra-mini-howto new file mode 100644 index 0000000..a3628e5 --- /dev/null +++ b/examples/howto/ultra-mini-howto @@ -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 index 0000000..eacdd3b --- /dev/null +++ b/examples/remote_backup_ssh/backitup @@ -0,0 +1,59 @@ +#!/bin/sh + +# +# This script will backup local drives to a remote tape drive over ssh. +# written by David B. Peterson +# +# 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 index 0000000..11870f1 --- /dev/null +++ b/install-sh @@ -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 index 0000000..a313a0c --- /dev/null +++ b/linux-1.2.x.patch @@ -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 index 0000000..cdc2004 --- /dev/null +++ b/restore/Makefile.in @@ -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 index 0000000..2a23f94 --- /dev/null +++ b/restore/dirs.c @@ -0,0 +1,817 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include + +#ifdef __linux__ +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#else /* __linux__ */ +#ifdef sunos +#include +#include +#else +#include +#include +#endif +#endif /* __linux__ */ +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#else +#ifdef sunos +#include +#else +#include +#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 = ""; + 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 index 0000000..e2702ed --- /dev/null +++ b/restore/extern.h @@ -0,0 +1,156 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#ifndef __P +#include +#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 index 0000000..ecbffda --- /dev/null +++ b/restore/interactive.c @@ -0,0 +1,1042 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include + +#ifdef __linux__ +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#else /* __linux__ */ +#ifdef sunos +#include +#include +#else +#include +#include +#endif +#endif /* __linux__ */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#endif + +#if defined(__linux__) || defined(sunos) +extern char * __progname; +#endif + +#include "restore.h" +#include "extern.h" + +#if HAVE_READLINE +#include +#include + +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 +#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 index 0000000..f53d740 --- /dev/null +++ b/restore/main.c @@ -0,0 +1,789 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#include +#include +#else /* __linux__ */ +#ifdef sunos +#include +#include +#include +#include +#include +#else +#include +#endif +#endif /* __linux__ */ +#include + +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +#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 index 0000000..d7f934b --- /dev/null +++ b/restore/restore.8.in @@ -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 001, 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 : 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 , got +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 +.TP +.I Tape read error while skipping over inode +.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 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 +. 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 . +.SH AVAILABILITY +The +.B dump/restore +backup suite is available from +.SH HISTORY +The +.B restore +command appeared in 4.2BSD. diff --git a/restore/restore.c b/restore/restore.c new file mode 100644 index 0000000..b95e356 --- /dev/null +++ b/restore/restore.c @@ -0,0 +1,1209 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include + +#ifdef __linux__ +#include +#include +#include +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#else /* __linux__ */ +#ifdef sunos +#include +#include +#else +#include +#endif +#endif /* __linux__ */ + +#include + +#include +#include +#include +#include + +#ifdef __linux__ +#include +#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 index 0000000..bf6284b --- /dev/null +++ b/restore/restore.h @@ -0,0 +1,196 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +/* + * 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 index 0000000..3e6d3fc --- /dev/null +++ b/restore/symtab.c @@ -0,0 +1,639 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include + +#ifdef __linux__ +#include +#include +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#else /* __linux__ */ +#ifdef sunos +#include +#include +#else +#include +#endif +#endif /* __linux__ */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#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 index 0000000..2f344db --- /dev/null +++ b/restore/tape.c @@ -0,0 +1,3122 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#include +#else /* __linux__ */ +#ifdef sunos +#define quad_t int64_t +#include +#include +#include +#else +#include +#endif +#endif /* __linux__ */ +#ifdef DUMP_MACOSX +#include "darwin.h" +#endif +#include + +#ifdef HAVE_ZLIB +#include +#endif /* HAVE_ZLIB */ + +#ifdef HAVE_BZLIB +#include +#endif /* HAVE_BZLIB */ + +#ifdef HAVE_LZO +#include +#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 = ""; + 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/ */ + { + 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 = ""; + 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 = ""; + break; + + case TS_BITS: + curfile.name = ""; + 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 +#else +#include +#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 index 0000000..e0db9af --- /dev/null +++ b/restore/utilities.c @@ -0,0 +1,720 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef __linux__ +#include +#include +#include +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else +#include +#endif +#include +#include +#else /* __linux__ */ +#ifdef sunos +#include +#include +#include +#else +#include +#include +#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 +#else +#include +#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 index 0000000..f64f5fa --- /dev/null +++ b/rmt/Makefile.in @@ -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 index 0000000..48da098 --- /dev/null +++ b/rmt/cipher.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 , 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 index 0000000..af41e0a --- /dev/null +++ b/rmt/rmt.8.in @@ -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 +. 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 . +.SH AVAILABILITY +The +.B dump/restore +backup suit is available from +.SH HISTORY +The +.B rmt +command appeared in 4.2BSD. diff --git a/rmt/rmt.c b/rmt/rmt.c new file mode 100644 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 , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - Alcôve , 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 +#include +#include +#include +#include +#include +#include +#include +#ifndef __linux__ +#include +#endif +#include +#include +#include +#include + +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 + * 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); +} -- 2.30.2