--- /dev/null
+-bad -bap -bbb -nsob -cdb -sc -br -cli0 -ss -npcs -cs -bs -di8 -i8 -lp
+-ts8 -ce -l78 -Ttar_record
+
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+Version 2.5.1 changed J"org Weule (weule@7b5.de) at 13-AUG-2000
+ - Thorsten Kranzkowski <dl8bcu@gmx.net> has send me a patch
+ with a bug fix. Now the listing created by
+ 'mt-dds tell;tar -Rt' created by an unpatched tar can be used.
+Version 2.5.0 changed J"org Weule (weule@7b5.de) at 6-AUG-2000
+ - Roland Wundrig has send me a patch to eliminate quoted
+ substrings from the index file. In order to alow the user
+ to use a quoted or unquoted form on the command line,
+ I coded this feature in a different way.
+Version 2.4.21 chanded by J"org Weule (weule@acm.org) at 1998 Aug 5.
+ - Added Exabyte as a tape vendor.
+Version 2.4.20 chanded by J"org Weule (weule@acm.org) at 1998 Jul 28.
+ - Andrew Ukrainec (ukrainec@infoukes.com) pointed out,
+ that there is a mistake in the patch of tar inside the
+ online documentation of the new option. I fixed that.
+Version 2.4.19 chanded by Erkki Myllynen (erkki@sweden.hp.com)
+ - A bug was found inside the tar patch, the calculation
+ of the thoughtput is fixed now.
+Version 2.4.18 chanded by Chris Hanson (cph@martigny.ai.mit.edu)
+ - Bug fix for dds_index.c to handle LF_LONGNAME records at
+ the end of tape blocks correctly.
+Version 2.4.17 chanded by J"org Weule at 1998 May 25.
+ - I've deleted the set_density, because HP drives
+ are operating with variable block sizes well and
+ othter drives don't support changing the density.
+ - The blocksize is now the buffer size of the program.
+ read_ahead is only possible for root and deleted in this
+ version.
+ - The calculation of the block numer is changed
+Version 2.4.16 chanded by J"org Weule
+ - scsi_vendor: Added a script to examine the drive vendor.
+ - on non archive tapes, the blocksize is set to one.
+ These drives can not handle other block sizes.
+ Read-ahead is enabled to enhence performance.
+ - dds_extract.c: Added #define _GNBU_SOURCE for compilation
+ on new systems like RedHat5.0.
+Version 2.4.15 changed by J"org Weule at 1997 Dec 9.
+ - dds_extract.c: bug-fix, short index lines
+ - dds_extract.c: support for tar-1.12 verbose listing
+
+Version 2.4.14 changed by J"org Weule at 1997 Nov 30.
+ - dds_extract.c: bug-fix
+ - dds_tape.c: to make the program working under HP-UX
+ thanks to Les.Grant@mitsuibabcock.co.uk
+ for his patch, sended to me at 1997 Nov 28:
+Version 2.4.13 changed by J"org Weule at 1996 Dez 1. :
+ - Added support for long filenames. Long filenames
+ are handled with "tar cv ..." and dds2index to create
+ the index table. "tar xv ..." is not writing an index
+ dds2tar can handle correct with long file names.
+ A filename is called long, if it has more than 99 characters.
+ - Fixed problems matching the index with the header records
+ of the tape. I made the check more robust.
+Version 2.4.12 changed by J"org Weule at 1996 Mar 29. :
+ - fixed the strncmp calls inside dds2tar.c - thanks to
+ Goncal Badenes <badenes@imec.be> for the bug fix.
+ - fixed dds_extract.c --
+ tar cfv and tar vft are reporting soft _and_ hard links
+ in a different style. Hard links may not confuse the
+ header test in dds_extract.
+ Goncal Badenes <badenes@imec.be> for the bug fix.
+ - Added a test with an unpatched tar into dds2tar-test.sh.
+
+Version 2.4.11 changed by J"org Weule at 1996 Mar 10. :
+ - Added a warning: You have to be root to change compression.
+ - Added dds-dd, a tool to read a tape with unknown block size.
+
+Version 2.4.10 changed by J"org Weule at 1996 Feb 5. :
+ - Fixed my tar-patch. Sorry for the mistake.
+
+Version 2.4.10 changed by J"org Weule at 1996 Jan 4. :
+ - Changed the counter --totals with tar-1.11.8-patch to
+ 'long long int' to use very large archives.
+ Added the calculation of the throuput on --totals.
+ - Fixed the dds2tar-test.sh script.
+ - Test for elf compatibility.
+
+Version 2.4.9 changed by J"org Weule at 1995 Feb 4. :
+ - Added the action filename to mt-dds.
+
+Version 2.4.8 changed by J"org Weule at 1995 Feb 4. :
+ - Added option 'date <timestammp>' to mt-dds.
+ - Fixed the code for 'mt-dds ts'
+ - tar-1.11.2.patch:
+ Added %T to expand the record-filename with the timestamp.
+
+Version 2.4.7 changed by J"org Weule at 1995 Feb 2. :
+ - Added a patch to tar (support for sparse file on Linux boxes).
+ - dds_bsr() inserted to dds_tape.c and used by mt-dds (label).
+ A small change of ddstool was necessary
+
+Version 2.4.6 changed by J"org Weule at 1995 Jan 29. :
+ - added the option ts to mt-dds.
+ - added the option date to mt-dds.
+ - added teh script 'ddstool' to make some things easier.
+ - fixed the handling of softlinks in conjunction with
+ tar index file -- dds2tar ended with FATAL error in
+ this case.
+ - added a tool tar2tar.
+
+Version 2.4.5 changed by J"org Weule at 1994 Dez 22. :
+ - On non HP-DDS devices, teh record number is read from
+ the device before any block is read.
+ - Added the option --quick to skip reading of parent directories.
+
+Version 2.4.4 changed by J"org Weule at 1994 Dez 3. :
+
+Version 2.4.3 changed by J"org Weule at 1994 Nov 21. :
+ - Added a test script with index files to the package.
+ - Added --body to dds2tar.
+ - Added label to mt-dds.
+
+Version 2.4.2 changed by J"org Weule at 1994 Nov 21. :
+ - Fixed some bugs of dds_extract.c.
+
+Version 2.4.1 changed by J"org Weule at 1994 Nov 7. :
+ - Andreas Bagge was kind enought to report a bug:
+ Long files (>1MB) are shifting the name field in the tar
+ listing to the right. dds_extract.c is now able to detect
+ this.
+ - I moved the check about the line '-end- ...' to the begining
+ of the loop inside dds_extract.c.
+ - Fixed a bug of mt-dds. tell was not working at all.
+ - Tried to include code to set the right buffer size
+ in order to allow the change of the buffer of the kernel.
+ The size of the internal buffer can be set by the -b option
+ (command line or environment) or is extracted from the
+ tar record file if possible. The internal buffer should be
+ large enought to hold one tape block.
+ - As Andreas Bagge pointed out, a parameter to fnmatch()
+ serves for matching filenames by giving the directory
+ entry. The matching is now done similar to tar.
+ - A workaround lets you create an index of tapes created
+ with 'tar -b 256 ...' on SunOS. You may have to increase
+ the default buffer size (ST_BUFFER_BLOCKS) inside the
+ Makefile to 64 or bigger and the kernel
+ (/usr/src/linux/drivers/scsi/st.c) in that case. On SunOS I
+ recommend a block size smaller or equal than 64 (-b option of
+ tar = 32Kb). You have also to increase the buffer size
+ of your kernel (/usr/src/linux/drivers/scsi/st.c).
+ The default buffer size of the kernel is the maximal block
+ size of tape block which can be read is 32kB.
+ - The option --body is included.
+
+Version 2.4.0 changed by J"org Weule at 1994 Oct 28. :
+ - Fnmatch() was found inside clib (gclib). Code deleted.
+
+Version 2.3.9 changed by J"org Weule at 1994 Oct 16. :
+ - Reading some options from the environment, e.g. -z, -s, -b.
+
+Version 2.3.8 changed by J"org Weule at 1994 Oct 15. :
+ - Added a check for the header at dds2index.
+ If it's not a tar header, a skip is performed.
+
+Version 2.3.7 changed by J"org Weule at 1994 Oct 13. :
+ - change the tar-1.11.2 patch to get the date of archiving
+ in the listing (bug fix). The date of the label record is
+ printed correct now while creating the archive.
+ - New options --z and --no-compress are included.
+ - The environment variable DDS2TAR should contain the string
+ --compress to set this option to default.
+ - The default DEVICE is now /dev/rmt0 like tar.
+
+Version 2.3.6 changed by J"org Weule at 1994 Oct 11. :
+ - A lot of header files are created. Some source files
+ are divided into two.
+ - As Andreas Bagge pointed out, main(argc,argv,envp) is not
+ ANSI-C code. I deleted envp for that reason, but this still
+ works.
+ - I changed the interface to open child processes. Now you
+ find a nice interface at "zf-cre-open.c". You may open
+ a pipe to the child process for reading or writing on a
+ file number of your choice, e.g. 0 or 1 ('creopen()').
+ (Writing stderr to a child process is not supported.)
+ The function 'zfopen()' opens a file for reading or writing
+ with transparent (de)compression. This may also be of interest
+ for other programs.
+
+Version 2.3.5 changed by J"org Weule at 1994 Oct 11. :
+ - Added -fwritable-strings to the compiler options
+ Constant strings are declared const by hand.
+
+Version 2.3.4 changed by J"org Weule at 1994 Oct 10. :
+ - Inserted a lot of const declarations and fixed a bug
+ inside an experimental function.
+ - Added the postscript versions of the manual pages to the
+ distribution.
+
+Version 2.3.3 changed by J"org Weule at 1994 Oct 10. :
+ - No access to tape with -l.
+ - Inserted some lines for security.
+ If the name of the program is mt-dds, nothing is
+ written on the disk by the program.
+
+Version 2.3.2 changed by J"org Weule at 1994 Oct 10. :
+ - bug fix inside dds_extract.c.
+
+Version 2.3.1 changed by J"org Weule at 1994 Oct 9. :
+ - All header record are checked for the filename.
+ - New option -l is included to check the index file for the
+ selected matches. The strings are written to stdout and no
+ pipeing to tar should be done.
+ - option --extract included.
+
+Version 2.3.0 changed by J"org Weule at 1994 Oct 9. :
+ - Added a check inside dds2tar. Now some header records of the
+ tar files to extract are checked for the expected file name.
+ dds2tar should stop if you have inserted the wrong tape.
+ - I inserted a routine to open stdout for a child process or
+ a file. Andreas Bagge gave me some source to create the
+ included functions.
+ - A funktion tar-dds is added to write a tool like tar.
+ The tool is not ready yet.
+ - Added background information to the man page of dds2tar.
+ The lines are based on a text from Andreas Bagge.
+
+Version 2.2.0 changed by J"org Weule:
+ I have deleted a lot of options to make the software easier to use.
+ The scan of the index file is very robust.
+
+ Hope you agree that dds2tar should be a small tool, simple to
+ use and with as less parameters as possible. That's why I have
+ deleted old and obsolete parameters for the costs that you may
+ have to change some scripts.
+
+Version 2.1.2 Index lines strings with '#' are ignored.
+ mt-dds can be used to set the tape position of the tape
+ for the next run of dds2tar. This may be convenient for
+ shell scripts.
+
+Version 2.1.1 The recfile (-R) can also be an index-file created by dds2index.
+ The option -t of dds2tar is obsolete.
+ Help is written to stdout.
+
+Version 2.1.0 made some options obsolete.
+
+Version 2.0.1 is a package with a patch to tar-1.11.2.
+
+Version 2.0.0 is a package of three programs, to make it easier to use.
+ A lot of options of dds2tar-1.1.3 are included.
+ So it is easy to switch to this new version.
+
+
--- /dev/null
+# Makefile for dds2tar
+#
+#--------------------------------------------------------
+# To compile everything: make
+# To install the executables and man pages: make install
+#--------------------------------------------------------
+
+V=2.5.2
+
+# Here are some configurable options:
+################################################################
+
+# To enable the use of the log pages of an HPDAT,
+# uncomment the following line :
+HPDAT=-DHPDAT
+
+# Default tape device is: /dev/nst0
+# edit or uncomment the following line to change the default device
+DEVICE=/dev/rmt0
+
+# Enable trace mode -- for debugging only
+# TRACE=-DDDS_TRACE=1
+
+# The tape blocks are read into a buffer, so the buffer of dds2tar
+# should be in the same size as the one in /usr/src/linux/driver/scsi/st.c
+# of the kernel code. Set ST_BUFFER_BLOCKS to zero, in order to take the
+# size from the kernel source directly.
+#
+# The number is halved, if EOVERFLOW is detected.
+# The value of the kernel is normally ST_BUFFER_BLOCKS=32.
+#
+# To configure the buffer size of dds2tar
+# change or uncomment the following line :
+# BUFFER=-DST_BUFFER_BLOCKS=32
+BUFFER=-DST_BUFFER_BLOCKS=0
+
+# To include some experimental stuff
+# uncomment the following line :
+# EXP_STUFF=-DEXP_STUFF
+
+# change this to where you want to install:
+BINDIR=/usr/bin
+MANDIR=/usr/man
+MANEXT=1
+
+# place here your favorite C compiler and options
+CC=cc -g
+CCOPT=$(HPDAT) $(HPDAT4) $(EXP_STUFF) $(MATCH) $(BUFFER) \
+ -DDEVICE=\"$(DEVICE)\" -O4 -Wall $(TRACE)
+
+# -Wall \
+# -Wstrict-prototypes \
+# -Wshadow \
+# -Wwrite-strings \
+# -Wpointer-arith \
+# -Wcast-qual \
+# -Wenum-clash \
+# -Wcast-align \
+# -Wtraditional \
+# -Wmissing-prototypes \
+# -Wnested-externs \
+# -Winline \
+# -pedantic \
+
+
+# nothing configurable below this line
+################################################################
+
+.SUFFIXES: .c .o .man .$(MANEXT) .ps .s
+
+D=dds2tar-${V}
+
+CCFLAGS=-DVERSION=\"$V\"
+
+TAR=tar
+ARCHIVE=\
+$(D)/Makefile \
+$(D)/Changes \
+$(D)/README \
+$(D)/dds2tar.man \
+$(D)/dds2index.man \
+$(D)/mt-dds.man \
+$(D)/dds-dd.man \
+$(D)/dds2tar.ps \
+$(D)/dds2index.ps \
+$(D)/mt-dds.ps \
+$(D)/dds-dd.ps \
+$(D)/dds2tar.h \
+$(D)/dds2tar.c \
+$(D)/dds_extract.c \
+$(D)/zf-cre-open.h \
+$(D)/zf-cre-open.c \
+$(D)/dds_index.c \
+$(D)/dds_tape.h \
+$(D)/dds_tape.c \
+$(D)/dds_chkhdr.c \
+$(D)/dds_quote.c \
+$(D)/scsi_vendor \
+$(D)/tar-1.11.2.patch \
+$(D)/tar-1.11.8.patch \
+$(D)/tar-1.12.patch \
+$(D)/tar-1.13.patch \
+$(D)/tar-1.11.2-sparse-files.patch \
+$(D)/tar-1.11.2-sparse-files.README \
+$(D)/dds2tar-test.sh \
+$(D)/index-of-tar \
+$(D)/index-of-tar-v \
+$(D)/index-of-tar-t \
+$(D)/index-of-dds2index \
+$(D)/.indent.pro \
+$(D)/dds2tar.lsm \
+$(D)/COPYING \
+$(D)/ddstool \
+
+
+OBJ= dds_index.o dds_extract.o dds_tape.o dds_quote.o \
+ zf-cre-open.o dds_chkhdr.o
+
+
+all: dds2tar dds2tar.1 dds2index.1 mt-dds.1 dds-dd.1
+
+dds2tar: dds2tar.o $(OBJ)
+ $(CC) dds2tar.o $(OBJ) -o dds2tar
+ ln -f dds2tar dds2index
+ ln -f dds2tar mt-dds
+ ln -f dds2tar dds-dd
+
+tar2tar: tar2tar.c
+ $(CC) tar2tar.c -o tar2tar
+
+dds2index: dds2index.o $(OBJ)
+ $(CC) dds2index.o $(OBJ) -o dds2index
+
+mt-dds: mt-dds.o $(OBJ)
+ $(CC) mt-dds.o $(OBJ) -o mt-dds
+
+dds-dd: dds-dd.o $(OBJ)
+ $(CC) dds-dd.o $(OBJ) -o dds-dd
+
+install: dds2tar ddstool \
+ dds2tar.$(MANEXT) mt-dds.$(MANEXT) dds2index.$(MANEXT) dds-dd.$(MANEXT)
+ install -c -s dds2tar $(BINDIR)
+ install scsi_vendor $(BINDIR)
+ install -c ddstool $(BINDIR)
+ ls -l $(BINDIR)/dds2tar $(BINDIR)/ddstool
+ install -c dds2tar.$(MANEXT) $(MANDIR)/man$(MANEXT)
+ install -c dds2index.$(MANEXT) $(MANDIR)/man$(MANEXT)
+ install -c mt-dds.$(MANEXT) $(MANDIR)/man$(MANEXT)
+ install -c dds-dd.$(MANEXT) $(MANDIR)/man$(MANEXT)
+ ln -f $(BINDIR)/dds2tar $(BINDIR)/dds2index
+ ln -f $(BINDIR)/dds2tar $(BINDIR)/mt-dds
+ ln -f $(BINDIR)/dds2tar $(BINDIR)/dds-dd
+
+T=tar-1.13
+tar: dds2tar.ps dds2index.ps mt-dds.ps dds-dd.ps ${T}.patch
+ -cd .. ; echo ' ' ; \
+ $(TAR) -R -c -f $(D).tar -v $(ARCHIVE) ;
+ echo ' '
+ ls -l ../$(D).tar
+ gzip -9 -f ../$(D).tar
+ ls -l ../$(D).tar.gz | awk '{print $$5}' > archive_length
+ sed s/LENGTH/`cat archive_length`/ <dds2tar.lsm |\
+ sed s/VERSION/$(V)/ > ../$(D).lsm
+ ls -l ../dds2tar*z ../dds2tar*.lsm
+ -rm -f ../dds2tar archive_length
+ cd .. ; ln -s $(D) dds2tar
+ echo ' '
+ cd .. ; tar zfc ${T}.1.tar.gz --totals ${T}.1
+ cd .. ; tar cf archive.tar ${D}.lsm ${D}.tar.gz ${T}.1.tar.gz
+
+tar-patch tar-1.13.patch:
+ ls -l tar-*patch
+ cd ..; diff -ru ${T} ${T}.1 |grep -v 'Only in '> $(D)/${T}.patch ;true
+ ls -l tar-*patch
+
+.c.o:
+ $(CC) -c $< $(CCOPT) $(CCFLAGS)
+
+.c.s:
+ $(CC) -S -c $< $(CCOPT) $(CCFLAGS)
+
+.man.1:
+ umask 022 ; sed -e 's?/dev/tape?$(DEVICE)?' $< >$@
+
+.man.ps:
+ umask 022 ; sed -e 's?/dev/tape?$(DEVICE)?' $< >$*.1
+ umask 022 ; groff -man $*.$(MANEXT) > $*.ps
+
+clean:
+ -rm -f $(OBJ) dds2tar.o dds2index.o mt-dds.o dds-dd.o *.BAK *.s
+ -rm -f dds2tar dds2index mt-dds dds-dd fio_test
+ -rm -f *~ *.$(MANEXT) *.ps
+ -rm -f tags *.bak
+ chmod 644 *
+
+doc:
+ a2ps -p -nP [A-Z]* *.h *.c *.lsm > a.ps
+ man dds2tar | a2ps -p -nP -m -Hdds2tar > b.ps
+ man dds2index | a2ps -p -nP -m -Hdds2index > c.ps
+ man mt-dds | a2ps -p -nP -m -Hmt-dds.man.ps > d.ps
+ man dds-dd | a2ps -p -nP -m -Hdds-dd.man.ps > d.ps
+
+psman: dds2tar.$(MANEXT) mt-dds.$(MANEXT) dds2index.$(MANEXT) dds-dd.$(MANEXT)
+ groff -man dds2tar.$(MANEXT) > dds2tar.ps
+ groff -man dds2index.$(MANEXT) > dds2index.ps
+ groff -man mt-dds.$(MANEXT) > mt-dds.ps
+ groff -man dds-dd.$(MANEXT) > dds-dd.ps
+
+dds_quote.o:dds_quote.c dds2tar.h
+dds_extract.o:dds_extract.c dds2tar.h dds_tape.h
+dds_index.o:dds_index.c dds2tar.h dds_tape.h
+dds_quote.o:dds_quote.c dds2tar.h
+dds_tape.o:dds_tape.c dds2tar.h dds_tape.h
+zf-cre-open.o:zf-cre-open.c zf-cre-open.h
+
+INC=dds2tar.h dds_tape.h zf-cre-open.h
+dds2tar.o:dds2tar.c $(INC)
+ $(CC) -c dds2tar.c $(CCOPT) $(CCFLAGS) -DPROGRAM=DDS2TAR -o dds2tar.o
+dds2index.o:dds2tar.c $(INC)
+ $(CC) -c dds2tar.c $(CCOPT) $(CCFLAGS) -DPROGRAM=DDS2INDEX -o dds2index.o
+mt-dds.o:dds2tar.c $(INC)
+ $(CC) -c dds2tar.c $(CCOPT) $(CCFLAGS) -DPROGRAM=MTDDS -o mt-dds.o
+dds-dd.o:dds2tar.c $(INC)
+ $(CC) -c dds2tar.c $(CCOPT) $(CCFLAGS) -DPROGRAM=MTDDS -o dds-dd.o
+
+fio_test:zf-cre-open.c zf-cre-open.h
+ cc zf-cre-open.c -DTEST -o fio_test
+
+tags:
+ ctags -stv *.c
+
--- /dev/null
+
+ dds2tar Digital-Data-Storage Extract Tool for LINUX and HP-UX
+
+ This tool makes use of the fast seek command of DAT devices.
+ Files from a selected file archive can be extracted within
+ one minute.
+
+ This tool was originally written for Linux SCSI tape archives.
+ All device dependent code is separated.
+ It should be easy, to change this for your machine type.
+ The only problem should be the ioctls for
+ MTIOCTOP,(MTSEEK,arg) and MTIOCPOS.
+
+ Les.Grant@mitsuibabcock.co.uk send me a patch to make it
+ working under HP-UX, thanks.
+
+ Other patches epsecially for Solaris are welcome.
+
+ J"org Weule weule@cs.uni-duesseldorf.de
+ Fon: +49 211 751409
+
+ This software is available at
+
+ ftp.uni-duesseldorf.de:/pub/unix/apollo
+
+ ( This is my personal directory, I started writing PD-software
+ on Apollo-Computers, but they are dying now :-( . Now you
+ will find some other stuff there.)
+
+----------------------------------------------------------------------------
+
+ LICENSE
+
+ This program 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+----------------------------------------------------------------------------
+
+ DESCRIPTION
+
+To extract a file from a tape, you have to know the location of the file.
+A tar archive is a sequence of tar records, 512 byte each. The blocksize
+(tar -b #) selects the number of tar records inside each block of the tape.
+(HP is calling the blocks of the tape records also.)
+
+The location of a file is a tuple of the block number and the number of the
+record where the header of the file can be found inside the block.
+
+The first step will be to extract a table with block and record information
+of all files in one archive. If the archive is the 10'th file of the tape,
+you will get the table by:
+
+ mt asf 10
+ dds2index -t my-archive-table -f /dev/nst0
+
+Tar is writing some record information to stdout, when you select the options
+-R and -v. To use this information as a location table, you have to know the
+block number of the first block and the blocksize of the archive. If it's the
+first archive of the tape and the blocksize is the default of 20, you can
+use the verbose lines of tar as a location table. (Additional lines with
+warnings can be included). Otherwise you have to patch tar to retrieve the
+location information. If you don't want to patch tar, feel free to insert
+the output of 'mt-dds tell' at the top of the verbose output of tar.
+
+If you have applied the patch file 'tar-1.12.patch' to GNU tar, you can use
+the verbose output of the tar command (tar -c -v --record-file F) instead of the
+index file generated with the dds2index command above.
+
+(If you patch tar-1.12, you are able to write the record-information
+ to a file while getting the errors on screen. The patch 'tar-1.12.patch'
+ adds the option '--record-file F'. Additionally a small bug in the source file
+ 'create.c' of tar is fixed. I have moved one line to correct the verbose output
+ of the record numbers. While creating the archive, you can store the current
+ time at the label record. A bug fix to write this date to the verbose output
+ is also done in the source file 'list.c'.)
+
+ ! The patch tar-1.12.patch moves one line inside the source file 'create.c'
+ ! and adds some lines for the ability to direct the verbose output to a file.
+ ! Two extra lines are printed to the terminal in some cases to get to current
+ ! tape position at the start and the blocksize.
+ ! Nothing else is done. There should be no extra risk for your data.
+ ! The tar will stay fully compatible to the original version.
+ ! The patch is also convenient for other operating systems.
+
+Lines of the index file stating with '#' are ignored. So you can insert
+some comments. This distribution includes some examples of index files.
+Look for files 'index-of-*'
+
+Once you have the table, you can get the files very quickly. Lets suppose,
+you want to extract everything of the glibc, you have to invoke
+the following command:
+
+ dds2tar -t my-archive-table 'glibc*' | tar -f - -xvv
+
+dds2tar will search in the archive table for the blocks to read, and
+extracts the records with the selected files. These records together
+are giving a valid tar archive, to use tar for restoring to your disk.
+This will also work, if the files are not a continuous area of the tape.
+dds2tar is skipping over the gaps very quickly with a seek command.
+If you want to extract exactly one file, use -x instead of -p.
+If you want to extract all files, witch named include a pattern,
+use -g instead of -p or -x.
+A list of files is valid to search for.
+
+With the option -z, you can force the index file to be in compressed mode.
+Compressed archive files are not supported.
+If you don't use the option -t, stdin or stdout are used in this case.
+The default device is /dev/nst0, witch can be overwritten by the TAPE variable
+and the option -f.
+
+If you want to get familiar with the command, use
+
+ # skipping to some file
+ mt rewind
+ mt fsf 20
+
+ # creating the table of the archive
+ dds2index -t my-archive-table
+
+ # The following line is an alternative way to create the index.
+ # You have to patch tar to make the option --record-file
+ # available.
+ # tar -t --record-file my-archive-table
+
+ # extract all files with the substring glibc in there names
+ # and use tar to check the output of dds2tar.
+ dds2tar -t my-archive-table 'glibc*' | tar -f - -tvv
+ # See what's going on ... ^^^^ ^^
+
+to see what's going on. In any case, dds2tar is reading your tape,
+so don't worry. Only the file specified by -t is written by this example.
+
+NOTE:
+To make extraction easier, dds2tar will also extract the directories
+for the selected files. So you will also get the full directory hierarchy.
+
+The owners of HP-DAT devices will find the actions comp-on, comp-off and
+comp-query (dds-compression-mode) of mt-dds convenient to change the compression
+mode of the device. Turning off the compression will speed up storing
+'gzip'ed files.
+
+WARNING:
+If we seek to the first block of a file, it can happen, that we are
+going to the position before the filemark. The program is closing and opening
+the file in that case to step over the filemark. Don't use /dev/st0 in that
+case, use /dev/nst0.
+
+THANKS:
+Thanks to Andreas (Andreas_Bagge@h2.maus.de), who has send me a new manual
+page, witch gave me the ideas how to split dds2tar-1.1.3 into peaces.
+His page was also the starting point for the approved man-page added to this
+version.
+
+Thanks also to Chris Hanson (cph@martigny.ai.mit.edu) for his bug bix.
+
+Last change 2.2.95 by J"org Weule
+
+----------------------------------------------------------------------------
+
+ INSTALLATION
+
+1. Change the "Makefile" to reflect the buffersize of the kernel.
+ Otherwise uncomment the definition of BUFFER.
+
+2. type "make install".
+
+3. patch tar-1.12 if you like.
+
--- /dev/null
+.TH dds-dd 1L 2.4 \" -*- nroff -*-
+.\"----------
+.SH NAME
+.\"----------
+dds-dd \- tool to read a dds device.
+.\"----------
+.SH SYNOPSIS
+.\"----------
+.B dds-dd
+[
+.B -f device
+]
+.PD 1
+.\"----------
+.SH DESCRIPTION
+.\"----------
+.B dds-dd
+reads a dds tape devices (DAT). Every block is read and written to
+stdout. A tape with unknown block size or blocks of different size
+can be read.
+.PP
+The default device is
+.IR /dev/rmt0 ,
+which may be overridden with the environment variable
+.BR TAPE ,
+which in turn may be overridden with the
+.BI -f \ device
+option. The device must be a character special file.
+.\"----------
+.SH OPTIONS
+.\"----------
+.TP
+.BI -f\ device
+Device of the tape archive (default is /dev/rmt0).
+Must be a character special file connected to a dds tape device.
+.TP
+.BR -V , --version
+Print the version number of
+.B mt-dds
+to stderr and exit immediately.
+.TP
+.B --help
+print some screens of online help with examples through a pager
+and exit immediately.
+.\"----------
+.SH EXAMPLES
+.\"----------
+.B Example:
+Read the tape and make a listing:
+.RS 10
+dds-dd | tar ft -
+.RE
+.PP
+.B Example:
+Read the tape and make a listing:
+.RS 10
+dds-dd | cpio -it
+.RE
+.PP
+.PD 1
+.\"----------
+.SH ENVIRONMENT
+.\"----------
+The environment variable
+.B TAPE
+overrides the default tape device /dev/rmt0.
+.TP
+.\"----------
+.SH "SEE ALSO"
+.\"----------
+dds2tar(1), dds2index(1), mt(1), tar(1)
+.\"----------
+.SH HISTORY
+.\"----------
+This program was created to use it in conjunction with dds2tar.
+.\"----------
+.SH AUTHOR
+.\"----------
+J"org Weule (weule@cs.uni-duesseldorf.de), Phone +49 211 751409.
+This software is available at
+ftp.uni-duesseldorf.de:/pub/unix/apollo
+
--- /dev/null
+%!PS-Adobe-3.0
+%%Creator: groff version 1.09
+%%CreationDate: Sun Mar 10 17:12:19 1996
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.09 0
+%%Pages: 1
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.09 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72
+def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron
+/scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent
+/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen
+/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon
+/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
+/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex
+/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y
+/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft
+/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl
+/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen
+/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft
+/logicalnot/minus/registered/macron/degree/plusminus/twosuperior
+/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior
+/ordmasculine/guilsinglright/onequarter/onehalf/threequarters
+/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE
+/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
+/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn
+/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla
+/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
+/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash
+/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def
+/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0/Times-Bold RE
+/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 375.52(dds-dd\(1L\) dds-dd\(1L\))72 48 R/F1 9
+/Times-Bold@0 SF -.18(NA)72 84 S(ME).18 E F0
+(dds-dd \255 tool to read a dds de)108 96 Q(vice.)-.25 E F1(SYNOPSIS)72
+112.8 Q/F2 10/Times-Bold@0 SF(dds-dd)108 124.8 Q F0([)2.5 E F2(-f de)2.5
+E(vice)-.15 E F0(])2.5 E F1(DESCRIPTION)72 148.8 Q F2(dds-dd)108 160.8 Q
+F0 .975(reads a dds tape de)3.475 F .975(vices \(D)-.25 F -1.11(AT)-.4 G
+.975(\). Ev)1.11 F .975
+(ery block is read and written to stdout. A tape with unkno)-.15 F(wn)
+-.25 E(block size or blocks of dif)108 172.8 Q(ferent size can be read.)
+-.25 E .726(The def)108 196.8 R .726(ault de)-.1 F .726(vice is)-.25 F
+/F3 10/Times-Italic@0 SF(/de)3.226 E(v/rmt0)-.15 E F0 3.226(,w).47 G
+.726(hich may be o)-3.226 F -.15(ve)-.15 G .726(rridden with the en).15
+F .726(vironment v)-.4 F(ariable)-.25 E F2 -.9(TA)3.226 G(PE).9 E F0
+3.226(,w)C .726(hich in)-3.226 F(turn may be o)108 208.8 Q -.15(ve)-.15
+G(rridden with the).15 E F2(-f)2.5 E F3(de)2.5 E(vice)-.15 E F0
+(option. The de)2.5 E(vice must be a character special \214le.)-.25 E F1
+(OPTIONS)72 232.8 Q F2(-f)108 244.8 Q F3(de)2.85 E(vice)-.15 E F0(De)144
+256.8 Q .792(vice of the tape archi)-.25 F 1.091 -.15(ve \()-.25 H(def)
+.15 E .791(ault is /de)-.1 F 3.291(v/rmt0\). Must)-.25 F .791
+(be a character special \214le connected to a)3.291 F(dds tape de)144
+268.8 Q(vice.)-.25 E F2(-V)108 292.8 Q F0(,)A F2(--v)A(ersion)-.1 E F0
+(Print the v)144 304.8 Q(ersion number of)-.15 E F2(mt-dds)2.5 E F0
+(to stderr and e)2.5 E(xit immediately)-.15 E(.)-.65 E F2(--help)108
+328.8 Q F0(print some screens of online help with e)11 E
+(xamples through a pager and e)-.15 E(xit immediately)-.15 E(.)-.65 E F1
+(EXAMPLES)72 352.8 Q F2(Example:)108 364.8 Q F0(Read the tape and mak)
+2.5 E 2.5(eal)-.1 G(isting:)-2.5 E(dds-dd | tar ft -)158 376.8 Q F2
+(Example:)108 400.8 Q F0(Read the tape and mak)2.5 E 2.5(eal)-.1 G
+(isting:)-2.5 E(dds-dd | cpio -it)158 412.8 Q F1(ENVIR)72 448.8 Q
+(ONMENT)-.27 E F0(The en)108 460.8 Q(vironment v)-.4 E(ariable)-.25 E F2
+-.9(TA)2.5 G(PE).9 E F0 -.15(ove)2.5 G(rrides the def).15 E
+(ault tape de)-.1 E(vice /de)-.25 E(v/rmt0.)-.25 E F1(SEE ALSO)108 496.8
+Q F0(dds2tar\(1\), dds2inde)144 508.8 Q(x\(1\), mt\(1\), tar\(1\))-.15 E
+F1(HIST)72 532.8 Q(OR)-.162 E(Y)-.315 E F0(This program w)108 544.8 Q
+(as created to use it in conjunction with dds2tar)-.1 E(.)-.55 E F1 -.45
+(AU)72 568.8 S(THOR).45 E F0(J"or)108 580.8 Q 3.028(gW)-.18 G .528
+(eule \(weule@cs.uni-duesseldorf.de\), Phone +49 211 751409.)-3.828 F
+.528(This softw)5.528 F .529(are is a)-.1 F -.25(va)-.2 G .529
+(ilable at ftp.uni-).25 F(duesseldorf.de:/pub/unix/apollo)108 592.8 Q
+220.25(2.4 1)299.75 768 R EP
+%%Trailer
+end
+%%EOF
--- /dev/null
+.TH dds2index 1L 2.4 \" -*- nroff -*-
+.\"----------
+.SH NAME
+.\"----------
+dds2index \- tool to create an indexfile for the use of
+.\"----------
+.SH SYNOPSIS
+.\"----------
+.B dds2index
+[options]
+.\"----------
+.SH DESCRIPTION
+.\"----------
+.B dds2index
+creates an index file that is required by the file extraction utility
+.BR dds2tar(1) .
+It works on
+.B tar
+archives stored on dds tape devices (DAT).
+Since the file structure of the tape archives is
+used to extract the files, the archive must be an
+.B uncompressed tar
+archive. But compression by the transparent
+signal processor of the tape device is allowed.
+.PP
+The index created by
+.BR dds2index
+is written to
+.I stdout
+by default and should normally be stored on hard disk as
+.I indexfile
+for later use by
+.BR dds2tar(1) .
+.PP
+The default tape device to read from is
+.IR /dev/tape ,
+which may be overridden with the environment variable
+.BR TAPE ,
+which in turn may be overridden with the
+.BI -f\ device
+option. The device must be a SCSI tape device.
+.PP
+.\"----------
+.SH OPTIONS
+.\"----------
+.TP
+.BI -f\ devicefile
+device of the tape archive. Must be a character special file.
+.TP
+.BI -t\ indexfile
+write the index to
+.IR indexfile ,
+not to
+.IR stdout.
+.TP
+.BR -z , --compress
+write the index in (gzip) compressed mode.
+.TP
+.B --help
+print some screens of online help with examples through a pager
+and exit immediatley.
+.\"----------
+.SH OPTIONS you didn't really need
+.\"----------
+.TP
+.B -b, --block-size
+Set the maximal blocksize, dds2index can handle.
+.TP
+.TP
+.B --z, --no-compress
+Don't filter the archive file through gzip.
+.TP
+.BR -v , --verbose
+verbose mode. Print to
+.IR stderr
+what is going on.
+.TP
+.BR -h , --hash-mode
+Print a hash sign '#' to
+.I stderr
+for each MB read from tape.
+.TP
+.BR -V , --version
+Print the version number of
+.B dds2index
+to
+.I stderr
+and exit immediately.
+.\"----------
+.SH EXAMPLES
+.\"----------
+.RP
+Example of getting the index from the default tape /dev/tape
+and storing it in file archive.idx:
+.IP
+dds2index -v -t archive.idx
+.\"----------
+.SH WARNING
+.\"----------
+This program can only read records (tar is calling them tape blocks)
+up to 32 kbytes. A bigger buffer will cause problems with the Linux
+device driver.
+.\"----------
+.SH ENVIRONMENT
+.\"----------
+The environment variable
+.B TAPE
+overrides the default tape device /dev/tape.
+.\"----------
+.SH FILES
+.\"----------
+.TP 14
+/dev/tape
+default tape device file. Must be a character special file.
+.\"----------
+.SH "SEE ALSO"
+.\"----------
+dds2tar(1), mt(1), mt-dds(1), tar(1), gzip(1)
+
+.\"----------
+.SH HISTORY
+.\"----------
+This program was created as a tool for
+.BR dds2tar(1) .
+
+.\"----------
+.SH AUTHOR
+.\"----------
+J"org Weule (weule@cs.uni-duesseldorf.de), Phone +49 211 751409.
+This software is available at
+ftp.uni-duesseldorf.de:/pub/unix/apollo
+
--- /dev/null
+%!PS-Adobe-3.0
+%%Creator: groff version 1.09
+%%CreationDate: Sun Mar 10 17:12:15 1996
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.09 0
+%%Pages: 2
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.09 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72
+def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron
+/scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent
+/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen
+/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon
+/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
+/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex
+/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y
+/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft
+/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl
+/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen
+/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft
+/logicalnot/minus/registered/macron/degree/plusminus/twosuperior
+/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior
+/ordmasculine/guilsinglright/onequarter/onehalf/threequarters
+/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE
+/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
+/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn
+/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla
+/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
+/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash
+/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def
+/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0/Times-Bold RE
+/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF(dds2inde)72 48 Q 348.04(x\(1L\) dds2inde)-.15 F
+(x\(1L\))-.15 E/F1 9/Times-Bold@0 SF -.18(NA)72 84 S(ME).18 E F0
+(dds2inde)108 96 Q 2.5(x\255t)-.15 G(ool to create an inde)-2.5 E
+(x\214le for the use of)-.15 E F1(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0
+SF(dds2index)108 124.8 Q F0([options])2.5 E F1(DESCRIPTION)72 141.6 Q F2
+(dds2index)108 153.6 Q F0 1.042(creates an inde)3.542 F 3.542<788c>-.15
+G 1.042(le that is required by the \214le e)-3.542 F 1.042
+(xtraction utility)-.15 F F2(dds2tar\(1\))3.542 E F0 6.041(.I)C 3.541
+(tw)-6.041 G 1.041(orks on)-3.641 F F2(tar)3.541 E F0(archi)108 165.6 Q
+-.15(ve)-.25 G 2.592(ss).15 G .092(tored on dds tape de)-2.592 F .092
+(vices \(D)-.25 F -1.11(AT)-.4 G 2.592(\). Since)1.11 F .092
+(the \214le structure of the tape archi)2.592 F -.15(ve)-.25 G 2.592(si)
+.15 G 2.592(su)-2.592 G .092(sed to e)-2.592 F .093(xtract the)-.15 F
+.37(\214les, the archi)108 177.6 R .67 -.15(ve m)-.25 H .37(ust be an)
+.15 F F2(uncompr)2.87 E .37(essed tar)-.18 F F0(archi)2.87 E -.15(ve)
+-.25 G 2.87(.B).15 G .37
+(ut compression by the transparent signal proces-)-2.87 F
+(sor of the tape de)108 189.6 Q(vice is allo)-.25 E(wed.)-.25 E .373
+(The inde)108 206.4 R 2.873(xc)-.15 G .373(reated by)-2.873 F F2
+(dds2index)2.873 E F0 .373(is written to)2.873 F/F3 10/Times-Italic@0 SF
+(stdout)2.873 E F0 .373(by def)2.873 F .374
+(ault and should normally be stored on hard disk)-.1 F(as)108 218.4 Q F3
+(inde)2.5 E(x\214le)-.2 E F0(for later use by)2.5 E F2(dds2tar\(1\))2.5
+E F0(.)A .487(The def)108 235.2 R .487(ault tape de)-.1 F .487
+(vice to read from is)-.25 F F3(/de)2.987 E(v/rmt0)-.15 E F0 2.987(,w)
+.47 G .487(hich may be o)-2.987 F -.15(ve)-.15 G .487
+(rridden with the en).15 F .486(vironment v)-.4 F(ariable)-.25 E F2 -.9
+(TA)108 247.2 S(PE).9 E F0 2.5(,w)C(hich in turn may be o)-2.5 E -.15
+(ve)-.15 G(rridden with the).15 E F2(-f)2.5 E F3(de)2.85 E(vice)-.15 E
+F0(option. The de)2.5 E(vice must be a SCSI tape de)-.25 E(vice.)-.25 E
+F1(OPTIONS)72 268.8 Q F2(-f)108 280.8 Q F3(de)2.85 E(vice\214le)-.15 E
+F0(de)144 292.8 Q(vice of the tape archi)-.25 E -.15(ve)-.25 G 2.5(.M)
+.15 G(ust be a character special \214le.)-2.5 E F2(-t)108 309.6 Q F3
+(inde)2.51 E(x\214le)-.2 E F0(write the inde)144 321.6 Q 2.5(xt)-.15 G
+(o)-2.5 E F3(inde)2.5 E(x\214le)-.2 E F0 2.5(,n).18 G(ot to)-2.5 E F3
+(stdout.)2.5 E F2(-z)108 338.4 Q F0(,)A F2(--compr)A(ess)-.18 E F0
+(write the inde)144 350.4 Q 2.5(xi)-.15 G 2.5(n\()-2.5 G
+(gzip\) compressed mode.)-2.5 E F2(--help)108 367.2 Q F0
+(print some screens of online help with e)11 E
+(xamples through a pager and e)-.15 E(xit immediatle)-.15 E -.65(y.)-.15
+G F1(OPTIONS y)72 384 Q(ou didn't r)-.225 E(eally need)-.162 E F2
+(-b, --block-size)108 396 Q F0(Set the maximal blocksize, dds2inde)144
+408 Q 2.5(xc)-.15 G(an handle.)-2.5 E F2(--z, --no-compr)108 436.8 Q
+(ess)-.18 E F0(Don')144 448.8 Q 2.5<748c>-.18 G(lter the archi)-2.5 E .3
+-.15(ve \214)-.25 H(le through gzip.).15 E F2(-v)108 465.6 Q F0(,)A F2
+(--v)A(erbose)-.1 E F0 -.15(ve)144 477.6 S(rbose mode. Print to).15 E F3
+(stderr)2.5 E F0(what is going on.)2.5 E F2(-h)108 494.4 Q F0(,)A F2
+(--hash-mode)A F0(Print a hash sign '#' to)144 506.4 Q F3(stderr)2.5 E
+F0(for each MB read from tape.)2.5 E F2(-V)108 523.2 Q F0(,)A F2(--v)A
+(ersion)-.1 E F0(Print the v)144 535.2 Q(ersion number of)-.15 E F2
+(dds2index)2.5 E F0(to)2.5 E F3(stderr)2.5 E F0(and e)2.5 E
+(xit immediately)-.15 E(.)-.65 E F1(EXAMPLES)72 552 Q F0
+(Example of getting the inde)108 564 Q 2.5(xf)-.15 G(rom the def)-2.5 E
+(ault tape /de)-.1 E(v/rmt0 and storing it in \214le archi)-.25 E -.15
+(ve)-.25 G(.idx:).15 E(dds2inde)144 580.8 Q 2.5(x-)-.15 G 2.5(v-)-2.5 G
+2.5(ta)-2.5 G(rchi)-2.5 E -.15(ve)-.25 G(.idx).15 E F1 -1.08(WA)72 597.6
+S(RNING)1.08 E F0 .63(This program can only read records \(tar is calli\
+ng them tape blocks\) up to 32 kbytes. A bigger b)108 609.6 R(uf)-.2 E
+.63(fer will)-.25 F(cause problems with the Linux de)108 621.6 Q
+(vice dri)-.25 E -.15(ve)-.25 G -.55(r.).15 G F1(ENVIR)72 638.4 Q
+(ONMENT)-.27 E F0(The en)108 650.4 Q(vironment v)-.4 E(ariable)-.25 E F2
+-.9(TA)2.5 G(PE).9 E F0 -.15(ove)2.5 G(rrides the def).15 E
+(ault tape de)-.1 E(vice /de)-.25 E(v/rmt0.)-.25 E F1(FILES)72 667.2 Q
+F0(/de)108 679.2 Q 28.86(v/rmt0 def)-.25 F(ault tape de)-.1 E
+(vice \214le. Must be a character special \214le.)-.25 E F1(SEE ALSO)72
+696 Q F0(dds2tar\(1\), mt\(1\), mt-dds\(1\), tar\(1\), gzip\(1\))108 708
+Q 220.25(2.4 1)299.75 768 R EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF(dds2inde)72 48 Q 348.04(x\(1L\) dds2inde)-.15 F
+(x\(1L\))-.15 E/F1 9/Times-Bold@0 SF(HIST)72 84 Q(OR)-.162 E(Y)-.315 E
+F0(This program w)108 96 Q(as created as a tool for)-.1 E/F2 10
+/Times-Bold@0 SF(dds2tar\(1\))2.5 E F0(.)A F1 -.45(AU)72 124.8 S(THOR)
+.45 E F0(J"or)108 136.8 Q 3.029(gW)-.18 G .529
+(eule \(weule@cs.uni-duesseldorf.de\), Phone +49 211 751409.)-3.829 F
+.528(This softw)5.528 F .528(are is a)-.1 F -.25(va)-.2 G .528
+(ilable at ftp.uni-).25 F(duesseldorf.de:/pub/unix/apollo)108 148.8 Q
+220.25(2.4 2)299.75 768 R EP
+%%Trailer
+end
+%%EOF
--- /dev/null
+#!/bin/sh
+make
+
+if test q$TAPE = q ; then export TAPE=/dev/nst0 ; fi
+case $TAPE in
+/dev/nst0|/dev/st0) V=`scsi_vendor tape 1` ;;
+/dev/nst1|/dev/st1) V=`scsi_vendor tape 2` ;;
+esac
+
+echo Tape vendor is $V
+echo =======================
+
+case $V in
+HP) B=32 ;;
+*) B=32 ;;
+esac
+
+X="--exclude=index*"
+
+echo $B
+echo $X
+
+#===================1==========================================================
+echo 'dds2tar-test 1>' make
+make
+
+#===================2==========================================================
+echo ' '
+echo 'dds2tar-test 2>' 'make of?'
+if test ! -x ./dds2tar ; then exit 1 ; fi
+
+#===================3==========================================================
+echo ' '
+echo 'dds2tar-test 3>' creating soft links
+ln -sf ./dds2tar ./dds2index
+ln -sf ./dds2tar ./mt-dds
+
+#===================4==========================================================
+echo ' '
+echo 'dds2tar-test 4>' creating soft and hard links
+ln -s dds2tar dds2tar-test-tape-link-soft
+ln dds2tar dds2tar-test-tape-link-hard
+
+#===================5==========================================================
+echo ' '
+echo 'dds2tar-test 5>' tar c .
+tar c $X .
+
+#===================6==========================================================
+echo ' '
+echo 'dds2tar-test 6>' tar -c --label dds2tar -b $B ... .
+tar --label dds2tar --record-file index-of-tar $X -R -v -c -b $B .
+
+I=`grep 'number of the file' index-of-tar | cut -c 38-43`
+if test q"$I" = q ; then I=1 ; fi
+if test $I = 0 ; then exit 1 ; fi
+I=`expr $I - 1`
+echo file number of the archive written is $I
+if test "$I" = "" ; then exit 1 ; fi
+
+#===================7==========================================================
+echo ' '
+echo 'dds2tar-test 7>' tar -c . ...
+tar --record-file index-of-tar-v -v -R -v -c -b $B $X .
+
+#===================8==========================================================
+echo ' '
+echo 'dds2tar-test 8>' mt rewind \; mt fsf $I
+mt rewind ; mt fsf $I
+
+#===================9==========================================================
+echo ' '
+echo 'dds2tar-test 9>' mt-dds tell
+./mt-dds tell
+
+#==================10==========================================================
+echo ' '
+echo 'dds2tar-test 10>' mt-dds label
+./mt-dds label
+
+#==================11==========================================================
+echo ' '
+echo 'dds2tar-test 11>' mt-dds
+./mt-dds
+
+#==================12==========================================================
+echo ' '
+echo 'dds2tar-test 12>' dds2index
+./dds2index -t index-of-dds2index
+
+#==================13==========================================================
+echo ' '
+echo 'dds2tar-test 13>' find '*tape*' using index-of-tar
+./dds2tar -t index-of-tar '*tape*' | tar fvt -
+
+#==================14==========================================================
+echo ' '
+echo 'dds2tar-test 14>' find '*tape*' using index-of-tar-v
+./dds2tar -t index-of-tar-v '*tape*' | tar fvt -
+
+#==================15==========================================================
+echo ' '
+echo 'dds2tar-test 15>' find '*tape*' using index-of-dds2index
+./dds2tar -t index-of-dds2index '*tape*' | tar vft -
+
+#==================16==========================================================
+echo ' '
+echo 'dds2tar-test 16>' dds2tar -t index-of-tar --body Changes '|wc -c'
+./dds2tar -t index-of-tar --body Changes | wc -c
+ls -l Changes
+
+#==================17==========================================================
+echo 'dds2tar-test 17>' mt rewind \; mt fsf $I
+mt rewind ; mt fsf $I
+
+#==================18==========================================================
+echo ' '
+echo 'dds2tar-test 18>mt-dds'
+mt-dds
+
+#==================19==========================================================
+echo ' '
+echo 'dds2tar-test 19> mt-dds tell >'index-of-tar-t
+mt-dds tell >index-of-tar-t
+
+#==================20==========================================================
+echo ' '
+echo 'dds2tar-test 20> tar tR >>' index-of-tar-t
+tar tR >> index-of-tar-t
+
+#==================21==========================================================
+echo ' '
+echo 'dds2tar-test 21>' grep -v "'loc '" '< index-of-tar-t > index-of-tar-t2'
+grep -v 'loc ' < index-of-tar-t > index-of-tar-t2
+
+#==================22==========================================================
+echo 'dds2tar-test 22>' mt rewind \; mt fsf $I
+mt rewind ; mt fsf $I
+
+#==================23==========================================================
+echo 'dds2tar-test 23>' find '*tape*' using index-of-tar-t2 and mt-dds
+echo 'dda2tar-test 23>' ./dds2tar '`mt-dds`' -t index-of-tar-t2 "'*tape*' | tar bvft 1 -"
+./dds2tar `mt-dds` -v -t index-of-tar-t2 '*tape*' | tar bvft 1 -
+
+#==================24==========================================================
+echo 'dds2tar-test 24>' mt rewind \; mt fsf $I
+mt rewind ; mt fsf $I
+
+#==================25==========================================================
+echo 'dds2tar-test 25>' removing links
+/bin/rm dds2tar-test-tape-link-soft
+/bin/rm dds2tar-test-tape-link-hard
+
--- /dev/null
+/*
+ dds2tar Digital-Data-Storage Extract Tool
+
+ This tool makes use of the fast seek command of DAT devices.
+ Files from a selected file archive can be extracted within
+ one minute.
+
+ J"org Weule weule@cs.uni-duesseldorf.de
+ Fon: +49 211 751409
+
+----------------------------------------------------------------------------
+
+ LICENSE
+
+ This program 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+----------------------------------------------------------------------------
+
+ To anyone in Germany I declare the following:
+
+ ! Ich werde gegen jede Verbreitung dieser Software rechtlich !
+ ! vorgehen, welche die Lizenzbestimmungen nicht einh"alt. !
+
+ Wie f"ur jede andere Software gilt auch hier:
+ Schon mit dem Kopieren oder Benutzen von Teilen dieser Software
+ werden die Lizenzbedingungen stillschweigend akzeptiert. Lesen Sie
+ also die Lizenzbedingungen sorgf"altig! Unkenntnis sch"utzt nicht
+ vor Strafe.
+
+*/
+
+/*-------------------------------------------------------------------------*/
+
+#include <stdlib.h> /* getenv() */
+#include <stdio.h>
+#include <string.h> /* strcmp() strlen() strstr() */
+#include <sys/types.h> /* open() stat() */
+#include <sys/stat.h> /* stat() */
+#include <fcntl.h> /* open() */
+#include <unistd.h> /* open() */
+#include <time.h> /* ctime() */
+
+#include "dds2tar.h"
+#include "dds_tape.h"
+#include "zf-cre-open.h"
+
+char vendor[9] = "\0\0\0\0\0\0\0\0\0" ;
+int vid; /* vendor id */
+
+/*-------------------------------------------------------------------------*/
+
+static const char help_text_dds2index[] =
+"This is dds2index, a tool for fast tape access.\n"
+"Choose one of the following\n"
+"-t,--table-of-contents F get file location from file F\n"
+"-z,--compress filter location file through gzip\n"
+"--z,--no-compress don't filter location file through gzip\n"
+"-f,--device F read the archive from device F\n"
+"-b,--block-size # set block size (non HP/SONY)\n"
+"-B,--Block-size # set block size (HP or SONY)\n"
+"-q,--quick don't extract parent directories from tape\n"
+"-v,--verbose verbose mode\n"
+"--hash-mode hash mode\n"
+"--force force nochk\n"
+"--help get help\n"
+"-V,--version print version number\n"
+"\n"
+"Environment:\n"
+"TAPE specifies the tape device\n"
+"DDS2TAR=[--compress] [-z] [-s #] [-b #]\n"
+" set some defaults\n"
+ ;
+
+static const char help_text_dds2tar[] =
+"This is dds2tar, a tool for fast tape access.\n"
+"Usage: dds2tar [options... ] -t index [pathname ...] | tar -f - ...\n"
+"\n"
+"dds2tar is a tool to read some tar-records from tape and write them\n"
+"as a tar archive to stdout. You have to use tar to extract the\n"
+"selected files. The index can either be created by dds2tar or tar.\n"
+"\n"
+"Choose one of the following\n"
+"-t,--table-of-contents F get file location from file F\n"
+"-z,--compress filter location file through gzip\n"
+"--z,--no-compress don't filter location file through gzip\n"
+"-f,--device F read the archive from device F\n"
+"-o,--output F write output to archive file\n"
+"-b,--block-size # set block size (non HP/SONY)\n"
+"-B,--Block-size # set block size (HP or SONY)\n"
+"-s,--first_block # set number of the first block\n"
+"--body print only the contents of the first file an quit\n"
+"-v,--verbose verbose mode\n"
+"--help get help\n"
+"-V,--version print version number\n"
+"\n"
+"Environment:\n"
+"TAPE specifies the tape device\n"
+"DDS2TAR=[--compress] [-z] [-s #] [-b #]\n"
+" set some defaults\n"
+ ;
+
+static const char help_text_mt_dds[] =
+"This is mt-dds, a tool to control the dds-device.\n"
+"Usage: mt-dds [-f device] <action>\n"
+"\n"
+"Choose one or none of the following actions:\n"
+#ifdef HPDAT
+"comp-on set compression mode on\n"
+"comp-off set compression mode off\n"
+"comp-query query compression mode\n"
+"comp-log print compression log page\n"
+#endif
+"-b set the buffer size\n"
+"blksize print the block size of the archive with format\n"
+"tell print current location and blocksize\n"
+"where print current location\n"
+"label print the label of the current archive\n"
+" if it begins at the current position\n"
+"filename print the filename of the current record\n"
+" if a header record is found at the current position\n"
+"ts print the timestamp of the current archive\n"
+"date print the date of the current archive\n"
+"scsi2logical select mode scsi2logical first\n"
+" if it begins at the current position\n"
+"date <timestamp> convert the stamp to a string\n"
+ ;
+
+static const char help_text_dds_dd[] =
+"This is dds-dd, a tool to read the dds-device.\n"
+"Usage: dds-dd` [-f device] | tar -f - -[x|t] ... \n";
+
+/*-------------------------------------------------------------------------*/
+
+static const char version[] =
+"Version " VERSION " -- last change 1994 Dez 22." ;
+
+/*-------------------------------------------------------------------------*/
+
+/* This is the source for dds2tar, dds2index and mt-dds. The program will
+ use the variable pg to decide witch version is running. The default
+ can be set in the Makefile and is overwritten by the value of argv[0].
+ If you give --dds2tar, --dds2index or --mt-dds as an option, the
+ program will run instead of these.
+*/
+
+#define DDS2TAR name_dds2tar
+static char const name_dds2tar[] = "dds2tar";
+
+#define DDS2INDEX name_dds2index
+static char const name_dds2index[] = "dds2index";
+
+#define MTDDS name_mtdds
+static char const name_mtdds[] = "mt-dds";
+
+#define DDS_DD name_dds_dd
+static char const name_dds_dd[] = "dds-dd";
+
+
+#if ( PROGRAM == DDS2TAR )
+char const *pg = name_dds2tar;
+char const *help_text = help_text_dds2tar;
+
+#elif ( PROGRAM == DDS2INDEX )
+char const *pg = name_dds2index;
+char const *help_text = help_text_dds2index;
+
+#elif ( PROGRAM == DDS2TAR )
+char const *pg = name_mtdds;
+char const *help_text = help_text_mt_dds;
+
+#elif ( PROGRAM == DDS_DD )
+char const *pg = name_dds_dd;
+char const *help_text = help_text_dds_dd;
+
+#else
+char const *pg = name_dds2tar;
+char *help_text = help_text_dds2tar;
+
+#endif
+
+#define LOCATION 1
+#define EXTRACT 2
+
+/*-------------------------------------------------------------------------*/
+
+char const dds_old_headline[] =
+"magic record blk: size name\n";
+
+char const dds_old_index_format[] =
+"%6s%7d%3d:%9d %s\n";
+
+/* magic blkno recno: size name */
+
+char const dds_old_index_scan_format[] =
+"%6c%7d%3d:%9d\n";
+
+char const dds_headline[] =
+"magic record blk: size name\n";
+
+char const dds_index_format[] =
+"%6s%7d%4d:%9d %s\n";
+
+/* magic blkno recno: size name */
+
+char const dds_index_scan_format[] =
+"%6c%7d%4d:%9d\n";
+
+/* magic blkno recno: size name */
+
+char const dds_loctext[] =
+"first block number is %d\n"
+"block size is %d\n" "block length is %d\n";
+
+char const dds_locline1[] =
+"loc number of the first block is %d\n";
+
+char const dds_locline2[] =
+"loc block length is %d bytes = %d * 512 bytes\n";
+
+/* to handle long link and long file names */
+int long_name_len = 0 ;
+char long_name[MAXPATHLEN<<2] = { '\0' };
+
+int
+rt_loc_line(void)
+{
+#define strneq(a,b,n) strncmp(a,b,n)==0
+
+ if ( strneq(cur_line, dds_locline1, 45) ) {
+ tar_fb = atoi(cur_line + 45);
+ } else
+ if ( strneq(cur_line, "first block number is", 21) ) {
+ tar_fb = atoi(cur_line + 21);
+ } else
+ if ( strneq(cur_line, dds_locline2, 31) ) {
+ tar_n = atoi(cur_line + 31);
+ tar_bs = tar_n >> 9;
+ } else
+ if ( strneq(cur_line, "block size is", 13) ) {
+ tar_bs = atoi(cur_line + 13);
+ tar_n = tar_bs << 9;
+ } else
+ if ( strneq(cur_line, "block length is", 15) ) {
+ tar_n = atoi(cur_line + 15) ;
+ tar_bs = tar_n >> 9 ;
+ } else {
+ return 1;
+ }
+
+ if ( verbose ) fprintf(stderr,
+ "block length is %d = %d * 512 \n", tar_n, tar_bs );
+
+#undef strneq
+
+ if ( buf_n < tar_n ) {
+ cur_block = realloc ( cur_block , buf_n = tar_n );
+ if ( cur_block == NULL ) {
+ fprintf(stderr, "%s: No memory available.\n", pg);
+ exit(2);
+ }
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+int verbose = 0;
+int hash_mode = 0;
+int list_only = 0; /* print only the matched names */
+int quick_mode = 0; /* don't extract parent directories also */
+int device; /* file number of the device */
+int write_body = 0 ; /* write only the body of the first file */
+int get_label = 0 ; /* get the label of the archive */
+int get_filename = 0 ; /* get the filename of the current record */
+int get_blocksize = 0 ; /* get the blocksize of the current record */
+int get_timestamp = 0 ; /* get the timestamp of the archive */
+int get_date = 0 ; /* get the date of the archive */
+int get_fileno = 0 ; /* get the number of the current */
+int force_nochk = 0 ; /* force tape read, no check of headers */
+
+/* file io */
+FILE *index_fp = NULL;
+
+/* archive location as set by arguments or index file */
+int tar_fb = 0; /* first block of the archive */
+int tar_bs = 20; /* block size in records of 512 bytes */
+int tar_n = 10240; /* block length in bytes */
+
+/* archive buffer and location as set by tape access */
+tar_record *cur_block;
+int cur_blkno = -1;
+int next_blkno = -1 ;
+int cur_bs;
+int cur_n;
+int buf_n = ST_BUFFER_BLOCKS << 10 ;
+
+/* line buffer to scan the index file */
+char *cur_line;
+
+/*-------------------------------------------------------------------------*/
+
+/********
+ * input: name of the device ( e.g. /dev/nst0, /dev/nrmt0 or NULL )
+ * open mode of the device ( e.g. O_RDONLY or O_WRONLY )
+ * verbose flag to indicate the logging mode (integer)
+ * output: channel number ( integer ) for use with 'read()' or 'write()'
+ *
+ * side effects: none
+ *
+ **********************************************************************/
+
+static int
+open_device(char const *pathname, int const open_mode)
+{
+ int fd;
+ int i = 1;
+ char const *p = "next try to open the tape %s\n";
+
+ {
+ int i ;
+ struct stat s ;
+ FILE *f ;
+ char cmd[100];
+ i = stat(pathname,&s);
+ if ( i < 0 ) perror("dds2tar"),exit(1);
+ sprintf(cmd,"scsi_vendor tape %d",(int)(s.st_rdev&0x7f)+1);
+ f = popen(cmd,"r");
+ fread(vendor,1,8,f);
+ fclose(f);
+ for ( i = 0 ; i < 8 ; i++ )
+ ( vendor[i] < 0x20 ) && ( vendor[i] = '\0' ) ;
+ if ( !strcmp(vendor,"HP") ) vid = HP ;
+ if ( !strcmp(vendor,"SONY") ) vid = SONY ;
+ if ( !strcmp(vendor,"ARCHIVE") ) vid = ARCHIVE ;
+ if ( !strcmp(vendor,"SEGATE") ) vid = SEGATE ;
+ if ( !strcmp(vendor,"EXABYTE") ) vid = EXABYTE ;
+ }
+
+ do {
+ if ((fd = open(pathname, open_mode)) >= 0)
+ break;
+ sleep(2);
+ if (verbose)
+ fprintf(stderr, p, pathname);
+ } while ((++i) <= 15);
+ if (fd < 0) {
+ perror("tape busy?");
+ exit(1);
+ } /* else dds_has_partitions(fd); */
+ return fd;
+}
+
+/*-------------------------------------------------------------------------*/
+int
+strprefix(char**s,char*p,char*q){
+ while ( p != 0 ) {
+ char *t = *s ; while (( *p != 0 ) && ( *p == *t )) p++ , t++ ;
+ if ( *p == 0 ) { *s = t ; return 1 ; }
+ p = q ; q = NULL ;
+ } return 0 ;
+}
+/*-------------------------------------------------------------------------*/
+
+/*
+ * dds2tar
+ */
+int
+main(int argc, char *const *argv)
+{
+
+#ifndef DEVICE
+#define DEVICE "/dev/rmt0"
+#endif
+
+ int density = 0 ;
+ int n = 1;
+ int l = strlen(argv[0]);
+ int compressed_mode = T_MODE;
+ char *p;
+ int child_proc = -1;/* child not running */
+ char const *index_file = NULL;
+ int print_location = 0;
+ int print_blksize = 0;
+ int mt_action = DDSCM_NULL; /* turn compression on/off */
+ int mode = 0; /* mode of dds2tar */
+ char const *const *pattern_list = NULL;
+ char const *device_name = DEVICE;
+
+ if ((p = getenv("TAPE")) != NULL)
+ device_name = p;
+
+ if (!strcmp(argv[0] + l - 7, "dds2tar")) {
+ pg = DDS2TAR;
+ help_text = help_text_dds2tar;
+ }
+ if (!strcmp(argv[0] + l - 9, "dds2index")) {
+ pg = DDS2INDEX;
+ help_text = help_text_dds2index;
+ }
+ if (!strcmp(argv[0] + l - 6, "mt-dds")) {
+ pg = MTDDS;
+ help_text = help_text_mt_dds;
+ }
+ if (!strcmp(argv[0] + l - 6, "dds-dd")) {
+ pg = DDS_DD;
+ help_text = help_text_dds_dd;
+ }
+
+ /*
+ * Scanning the environment.
+ */
+ p = getenv("DDS2TAR");
+ while (p != NULL) {
+ int count = 0 ;
+ if (*p == ' ') p++;
+ if ( *p == '\0' ) p = NULL ;
+ else if (strprefix(&p, "-z","--compress")) {
+ compressed_mode = C_MODE;
+ } else if (strprefix(&p, "--first-block ","-s")) {
+ sscanf(p, "%d%n", &tar_fb, &count);
+ p += count;
+ } else if (strprefix(&p, "--block-size ","-b ")){
+ sscanf(p, "%d%n", &tar_bs, &count);
+ tar_n = tar_bs * 512 ;
+ buf_n = tar_n ;
+ p += count;
+ } else if (strprefix(&p, "--Block-size ","-B ")){
+ sscanf(p, "%d%n", &tar_bs, &count);
+ tar_n = tar_bs * 512 ;
+ buf_n = tar_n ;
+ p += count;
+ density = tar_n ;
+ } else
+ p = NULL;
+ }
+
+ /*
+ * scan arguments
+ */
+ while (n < argc) {
+
+ /*
+ * Macros to test arguments ...
+ */
+
+#define T1(s) if((!strcmp(argv[n],(s))))
+#define T(s) else if((!strcmp(argv[n],(s))))
+#define TT(s,t) else if((!strcmp(argv[n],(s)))||(!strcmp(argv[n],(t))))
+#define ELSE else
+#define ELSEIF(s) else if(s)
+
+ /*
+ * Now scanning the arguments ...
+ */
+
+ T1("-0") {
+ fprintf(stdout, "dds2tar: %s\n", argv[0]);
+ exit(0);
+ }
+
+ /*
+ * misc
+ */
+ T("--help") {
+ fprintf(stdout, help_text);
+ exit(0);
+ }
+ TT("--version", "-V") {
+ fprintf(stdout, "%s: %s\n", pg, version);
+ exit(0);
+ }
+
+ /*
+ * Some more options ...
+ */
+ TT("--verbose", "-v") verbose = 1;
+ T("--hash-mode") hash_mode = 1;
+ T("--force") force_nochk = 1;
+
+ /*
+ * device name
+ */
+ T("-f") device_name = argv[++n];
+
+ /*
+ * index file
+ */
+ TT("-z", "--compress") compressed_mode = C_MODE;
+ TT("--z", "--no-compress") compressed_mode = T_MODE;
+ TT("-t", "--table-of-contents") {
+ index_file = argv[++n];
+ /*
+ * The format of the index is checked by the program.
+ */
+ }
+
+ /*
+ * Location of the file
+ */
+ TT("-s", "--first-block") {
+ tar_fb = atoi(argv[++n]);
+ }
+ TT("-b", "--block-size") {
+ tar_bs = atoi(argv[++n]);
+ tar_n = tar_bs * 512 ;
+ buf_n = tar_n ;
+ }
+ TT("-B", "--Block-size") {
+ tar_bs = atoi(argv[++n]);
+ tar_n = tar_bs * 512 ;
+ buf_n = tar_n ;
+ density = tar_n ;
+ }
+ TT("-m", "--buffer-size") {
+ fprintf(stderr,"buffer size is %d records, %d bytes\n",
+ buf_n>>9,buf_n);
+ exit(0);
+ }
+
+ ELSEIF(pg == DDS2TAR) {
+ /*
+ * Mode of the program.
+ *
+ * If you install dds2tar as mt-dds, the program will
+ * act as mt-dds. Since for some operations you need
+ * root permissions on mt-dds, it would not be a good
+ * idea to let the user switch to dds2index or dds2tar
+ * in this case.
+ */
+
+ T1("--dds2index") {
+ pg = DDS2INDEX;
+
+ help_text = help_text_dds2index;
+ }
+ T("--mt-dds") {
+ pg = MTDDS;
+ help_text = help_text_mt_dds;
+ }
+ T("--dds-dd") {
+ pg = DDS_DD;
+ help_text = help_text_dds_dd;
+ }
+ /*
+ * Mode of extraction ...
+ *
+ * The location list an experimental mode.
+ */
+#ifdef EXP_STUFF
+ T("--location-list") {
+ pattern_list = argv + n + 1;
+ mode = LOCATION;
+ break;
+ }
+#endif
+ /*
+ * Select a file for the output.
+ *
+ * Since mt-dds may be run as root, we write on screen
+ * in this case. Writing to a file is supported for
+ * dds2tar.
+ */
+ TT("-o", "--output") {
+ reopen(1, argv[++n], O_WRONLY | O_CREAT, 0660);
+ }
+
+ /*
+ * Do not read anything from tape.
+ */
+ TT("-l", "--list") {
+ list_only = 1;
+ if (verbose)
+ fputs("--list\n", stderr);
+ }
+ /*
+ * Write only the body of the file.
+ */
+ T("--body"){
+ write_body = 1 ;
+ }
+
+ /*
+ * Don't extract the parent directories from the tape.
+ */
+ TT("-q","--quick"){
+ quick_mode = 1 ;
+ }
+ /*
+ * Pipe the output to tar -x.
+ *
+ * This is for testing only.
+ */
+ T("--test") {
+ static char const *const a[5] =
+ {
+ "/bin/tar", "tfb", "-", "1", NULL
+ };
+
+ child_proc = creopen(1, 0, a[0], a);
+ }
+ T("--test-verbose") {
+ static char const *const a[5] =
+ {
+ "/bin/tar", "tfbv", "-", "1", NULL
+ };
+
+ child_proc = creopen(1, 0, a[0], a);
+ }
+ T("--extract") {
+ static char const *const a[5] =
+ {
+ "/bin/tar", "xfb", "-", "1", NULL
+ };
+
+ child_proc = creopen(1, 0, a[0], a);
+ }
+ ELSE {
+ {
+ char*const*p = argv+n ;
+ while (*p) dds_unquote(*p++) ;
+ }
+ pattern_list = (const char*const*)argv + n;
+ if (verbose)
+ fprintf(stderr,
+ "first pattern is '%s'\n",
+ *pattern_list
+ );
+ mode = EXTRACT;
+ break;
+ }
+ }
+
+ ELSEIF(pg == MTDDS) {
+ /*
+ * Tape actions ...
+ */
+ T1("tell") print_location = 1;
+ T("label") get_label = 1 ;
+ T("filename") get_filename = 1 ;
+ T("bs") get_blocksize = 1 ;
+ T("date") {
+ get_date = 1 ;
+ if ( argc > 2 ) {
+ int j = atoi(argv[2]);
+ fputs(ctime((time_t*)&j),stdout);
+ exit(0);
+ }
+ }
+ T("ts") get_timestamp = 1 ;
+ T("blksize") print_blksize = 1 ;
+#ifdef HPDAT
+#define R(c) if ( 0 != geteuid() ) { fprintf(stderr,\
+"You have to be root to do this : %s\n",c);exit(1);}
+ T("comp-on") {
+ R("comp-on");
+ mt_action = DDSCM_ON;
+ }
+ T("comp-off") {
+ R("comp-off");
+ mt_action = DDSCM_OFF;
+ }
+ T("comp-query") {
+ R("comp-query");
+ mt_action = DDSCM_QUERY;
+ }
+ T("comp-log") {
+ R("comp-log");
+ mt_action = DDSCM_LOG;
+ }
+ T("load") {
+ R("comp-load");
+ mt_action = DDSCM_LOAD;
+ }
+ T("unload") {
+ R("comp-unload");
+ mt_action = DDSCM_UNLOAD;
+ }
+ T("where") {
+ mt_action = DDSCM_WHERE;
+ }
+ /*
+ * Set mode scsi2logical first
+ */
+ T("scsi2logical"){
+ mt_action = DDSCM_LOGICAL;
+ }
+
+#endif
+#ifdef EXP_STUFF
+ /*
+ * tar-dds will handle the arguments in a very different way.
+ */
+ }
+ ELSEIF(pg == TAR_DDS) {
+
+ break;
+#endif
+ }
+ /*
+ * Next argument ...
+ */
+ n++;
+ }
+
+ cur_block = malloc(buf_n);
+ cur_line = malloc(MAXPATHLEN<<2);
+ if (cur_block == NULL || cur_line == NULL) {
+ fprintf(stderr, "%s: No memory available.\n", pg);
+ exit(2);
+ }
+ /*
+ * Switch the program mode ... dds2tar, dds2index or mt-dds ...
+ */
+ /*---------------------MT-DDS--------------------------------*/
+ if (pg == MTDDS) {
+#ifdef HPDAT
+ /*
+ * Is setting of compression mode or log page selected ?
+ *
+ * I think you have to run this as root.
+ */
+ if (mt_action != DDSCM_NULL) {
+ device = open_device(device_name, O_WRONLY);
+ if ( mt_action == DDSCM_LOGICAL )
+ dds_scsi2logical();
+ else
+ if ( mt_action == DDSCM_WHERE ) {
+ tar_fb = dds_getpos(device);
+ printf(" -s %d \n", tar_fb);
+ close(device);
+ return 0;
+ } else
+ set_compression_mode(device, mt_action);
+ } else
+#endif
+ /*
+ * Print the current position (tree lines).
+ */
+ {
+ device = open_device(device_name, O_RDONLY);
+ if ( vid == HP ){
+ tar_fb = dds_getpos(device);
+ dds_read_next_block();
+ /* dds_seek(device, tar_fb); */
+ dds_bsr();
+ } else {
+ tar_fb = dds_getpos(device);
+ cur_n = tar_n ;
+ }
+ tar_bs = cur_n >> 9;
+ if (( get_label || get_timestamp ||
+ get_date || get_filename ) &&
+ ( dds_is_tar_header_record(cur_block) != 0 )) {
+ if ( cur_block->hdr.linkflag == 'V' ) {
+ int i , j = 0 ;
+ char*p=cur_block->hdr.mtime ;
+ for ( i = 0 ; i < 12 ; i++ ) {
+ if ((p[i]>='0')&&(p[i]<='7')) {
+ j <<= 3 ;
+ j += p[i] - '0' ;
+ }
+ }
+ if ( get_label )
+ puts(cur_block->hdr.name);
+ else if ( get_timestamp ){
+ printf("%d\n",j);
+ } else /* get_date */ {
+ fputs(ctime((time_t*)&j),stdout);
+ }
+ } else
+ if ( get_filename ) puts(cur_block->hdr.name);
+ } else
+ if (print_location != 0) {
+ printf(dds_loctext, tar_fb, tar_bs, cur_n);
+ } else
+ if ( print_blksize != 0 ) {
+ printf("%d\n",tar_bs);
+ } else {
+ /*
+ * Print the current position (one line).
+ */
+ printf(" -s %d -b %d \n", tar_fb, tar_bs);
+ }
+ }
+ close(device);
+ /*---------------------DDS2TAR-------------------------------*/
+ } else if (pg == DDS2TAR) {
+
+ if (pattern_list == NULL)
+ return 0;
+ if (list_only != 1) {
+ device = open_device(device_name, O_RDONLY);
+
+ if ( density ) dds_set_bs(density);
+ }
+ index_fp = zfopen(index_file, compressed_mode, "r");
+ switch (mode) {
+#ifdef EXP_STUFF
+ case LOCATION:
+ extract_loc(pattern_list);
+ break;
+#endif
+ case EXTRACT:
+ dds_cmp(pattern_list);
+ break;
+ default:
+ fprintf(stderr, "nothing to do ? Try --help\n");
+ }
+ if (list_only != 1)
+ close(device);
+ if (child_proc != -1)
+ cclose(1);
+ /*---------------------DDS2INDEX-----------------------------*/
+ } else if (pg == DDS2INDEX) {
+ device = open_device(device_name, O_RDONLY);
+ if ( density ) dds_set_bs(density);
+ index_fp = zfopen(index_file, compressed_mode, "w");
+ dds_index();
+ close(device);
+ /*-----------------------------------------------------------*/
+ } else if ( pg == DDS_DD ) {
+ device = open_device(device_name, O_RDONLY);
+ if ( density ) dds_set_bs(density);
+ if ( verbose ) fprintf(stderr,"dds-dd ...\n");
+ while ( dds_read_next_block() , cur_n )
+ fwrite(cur_block,1,cur_n,stdout);
+ } else {
+ fprintf(stderr, "no program mode \n");
+ /*-----------------------------------------------------------*/
+ }
+ return 0;
+}
+
--- /dev/null
+/*
+ * This file is part of dds2tar.
+ * Copyright by J"org Weule
+ */
+
+/*
+ * Please change the value ST_BUFFER_BLOCKS at the top of the Makefile
+ * on error with these lines.
+ */
+#if defined ST_BUFFER_BLOCKS && ST_BUFFER_BLOCKS == 0
+#undef ST_BUFFER_BLOCKS
+#include "/usr/src/linux/drivers/scsi/st_options.h"
+#endif
+
+#ifndef ST_BUFFER_BLOCKS
+#define ST_BUFFER_BLOCKS 32
+#endif
+
+#include <sys/param.h>
+
+#define UNKNOWN 0
+#define HP 1
+#define SONY 1
+#define SEGATE 2
+#define ARCHIVE 2
+#define EXABYTE 2
+
+extern const char dds_headline[];
+extern const char dds_index_format[];
+extern const char dds_index_scan_format[];
+extern const char dds_old_headline[];
+extern const char dds_old_index_format[];
+extern const char dds_old_index_scan_format[];
+extern const char dds_loctext[];
+extern const char dds_locline1[];
+extern const char dds_locline2[];
+extern int dds_set_bs(int);
+extern char vendor[9];
+extern int vid; /* vendor ID */
+
+/*
+ * It's faster to read some records than to skip over them,
+ * if the number is smaller then DONT_SKIP.
+ * I really don't know the right number here.
+ */
+#define DONT_SKIP ((cur_n>0)?((int)(1024/cur_n)):((int)(1024/buf_n)))
+
+typedef union {
+ char chrptr[512];
+ struct {
+ char name[100];
+ char dummy1[24];
+ char size[12];
+ char mtime[12];
+ char dummy2[8];
+ char linkflag;
+ char dummy3[100];
+ char magic[8];
+ }
+ hdr;
+}
+
+tar_record;
+
+#define LF_LONGLINK 'K'
+#define LF_LONGNAME 'L'
+
+extern int tar_fb;
+extern int tar_bs;
+extern int tar_n;
+
+extern tar_record *cur_block;
+extern int cur_blkno;
+extern int next_blkno;
+extern int cur_n;
+extern int cur_bs;
+extern int buf_n;
+extern int force_nochk;
+
+extern char *cur_line;
+
+extern int hash_mode;
+extern int quick_mode;
+extern int device;
+extern int verbose;
+extern int list_only;
+extern FILE *index_fp;
+extern int write_body;
+extern int long_name_len;
+extern char long_name[MAXPATHLEN<<2];
+
+extern char* dds_quote(char*str);
+extern int dds_unquote(char*str);
+
+extern int dds_index(void);
+extern int dds_cmp(char const *const *pattern);
+extern int rt_line(
+ int *const ptr_blkno,
+ int *const ptr_recno,
+ int *const ptr_size,
+ char **const ptr_name
+);
+extern int rt_loc_line(void);
+extern int extract_loc(char const *const *);
+
+#ifdef EXP_STUFF
+extern int tar_dds(int const, char const *const *const);
+
+#endif
+
+extern int dds_is_tar_header_record(tar_record*const);
--- /dev/null
+Begin3
+Title: Tool to maintain tar tape archives and control compression.
+Version: VERSION
+Description: Once you have recorded the record number of each file of
+ a tar scsi-tape archive, you are able to find and extract these
+ files very fast. If you have a DAT drive, you can extract every
+ small file from a 2GB tape within 40 seconds.
+ tar2tar is included to change the pathnames inside a tar-archive.
+Author: weule@7b5.de (J"org Weule)
+Maintained-by: weule@7b5.de
+Primary-Site: sunsite.unc.edu:/pub/linux/system/backup
+ LENGTH dds2tar-VERSION.tar.gz
+Alternate-Site:www.eulesoft.de
+ LENGTH dds2tar-VERSION.tar.gz
+Platforms: Linux and HP (because of the TELL and SEEK command)
+ HP is not well supported.
+ SCSI-Tape drive
+Copying-Policy:GPL
+Keywords: tape archives , tar
+Comment: The software is only convenient, if your tape supports a fast
+ positioning command.
+ Added code (mt-dds) to change the compression mode of HP-DAT.
+ tar2tar will work on every computer with ANSI-C.
+ A patch to GNU-tar is included to add the option --record-file.
+End
+
--- /dev/null
+.TH dds2tar 1L 2.3 \" -*- nroff -*-
+.SH NAME
+dds2tar \- tool for fast tape access
+.SH SYNOPSIS
+.B dds2tar
+[
+.B -f
+.I device
+] [
+.B -t
+.I indexfile
+] [options]
+.I string ...
+.PP
+.SH DESCRIPTION
+.B dds2tar
+uses an index to find the files with record seek (a fast
+operation of DAT devices).
+Since the file structure of the tape archives is
+used to extract the files, the archive has to be created by
+.BR tar ,
+compressed only by (the transparent
+signal processor of) the device.
+So you can step through the archive
+very quickly and extract files.
+The index may be created using
+.BR dds2index
+or
+.BR tar -vRt
+and is normally stored as a file on your hard disk.
+.PP
+A tar archive is a sequence of blocks (e.g. 10240 bytes by default),
+each containing the same number (20 by default) of records, 512 byte each.
+.B dds2tar
+reads the tape and writes the tar records of the
+specified files (that means the header record and the data records of each
+selected file)
+to stdout.
+You may pipe the
+.B dds2tar
+output to the stdin of
+.I tar -xvvf -
+to restore the files to your disk.
+(See
+.B EXAMPLES
+below.)
+Before a file is extracted,
+the records of parent directories of the file are also written to stdout.
+.PP
+The index of the archive should contain enough information
+to compute the number of the block containing the header of each selected
+file.
+.B dds2index
+will give such a table,
+.B tar -Rvt
+e.g. will not (only record numbers are listed).
+A patch for
+.B GNU tar-1.12
+is available, adding the option
+.B --record-file.
+Alternatively there are some tricks to get the missing
+information.
+.PP
+The strings are regular expressions to select the files.
+The matching algorithm is the one from GNU tar. If the option
+.B -l
+is given, the matched file names are printed to stdout (You may not pipe
+this list of pathnames to tar!).
+.PP
+The default device is
+.IR /dev/tape ,
+which may be overridden with the environment variable
+.BR TAPE ,
+which in turn may be overridden with the
+.BI -f\ device
+option. The device must be a SCSI tape device.
+.SH OPTIONS
+.BI -f\ devicefile
+Device of the tape archive. Must be a SCSI tape device.
+.TP
+.BI -t\ indexfile
+Specifies the index file (default is stdin).
+.TP
+.BI -s\ #
+Set the number of the first tape block of the archive. This option is
+useful only if the index file contains the verbose output of
+.B tar -Rvt.
+Any information about the first block
+inside the index file will be overridden by this option.
+If no information is available, the archive has to be the first file of
+the tape. If you have positioned your tape at the first block of the archive,
+you can use
+.IP
+.B dds2tar `mt-dds` -t index ... | tar -f - ...
+.IP
+to complete the information of the output of
+.B tar -Rvt
+stored in the
+index file.
+.TP
+.BI -b\ #
+Set the blocksize of the archive (tar -b #). This option is
+useful only if the index file contains the verbose output of tar (or if
+you have problems with the size of the internal buffer of dds2tar).
+Any information about the blocksize
+inside the index file will be overridden by this option.
+If no information is available, the default blocksize of tar is used.
+.TP
+.B -z
+The index file should be read and stored in compressed mode.
+.SH OPTIONS you didn't really need
+.TP
+.B --z, --no-compress
+Don't filter the archive file through gzip.
+.TP
+.B -q, --quick
+Don't extract the parent directories of the selected objects from tape.
+.BR --body
+Write only the first selected file to stdout. This is useful if you want to
+read a file or extract an archive which is part of the current archive.
+.TP
+.BR -v , --verbose
+verbose mode.
+.TP
+.B --hash-mode
+Print a hash sign for each MB.
+.TP
+.BR -V , --version
+Print only the Version Number to stderr.
+.TP
+.B -l
+Don't access the tape but print the file names to stdout.
+You may not pipe this list of pathnames into tar.
+.TP
+.B --extract
+The stdout is closed and opened by a pipe to the command
+.B "tar -fxb - 1".
+You may find this option convenient, I like to pipe the output to tar
+by hand.
+.SH EXAMPLES
+Example of
+.B getting the index
+from the default tape /dev/tape
+and storing it in file archive.idx:
+.IP
+dds2index -t archive.idx
+.PP
+Alternatively you can use a patched version of tar to create an index file.
+With the patch you can direct the errors and warning to stdout and the
+index information including information about
+the blocksize and the number of the
+first block to a file:
+.IP
+tar -t --record-file archive.idx
+.PP
+If the archive is the first file of the tape and the blocksize is the default
+of 20, you can use the verbose output of tar (-Rv) as an index file.
+.IP
+tar -t -v -R | tee archive.idx
+.PP
+If the archive is not the first file of the tape, you can store all the
+necessary information inside the index file with the use of
+.B mt-dds
+and
+.B tar
+:
+.IP
+.Sp
+.nf
+mt asf ...
+mt-dds tell > archive.idx
+tar -tvR >>archive.idx
+.fi
+.Sp
+.PP
+Example of
+.B using dds2tar
+to extract the gnu library
+(all files containing the string "glibc" in filename)
+from the default tape /dev/tape,
+using the previously stored index file archive.idx:
+.IP
+dds2tar -t archive.idx '*glibc*' | tar xvvf -
+.PP
+.RP
+To see in advance what would happen in the previous command
+without actually writing anything to your disk,
+you may use:
+.IP
+dds2tar -t archive.idx '*glibc*' | tar tvvf -
+.PP
+Example of checking the matches. You may try:
+.IP
+dds2tar -t archive.idx -l '*glibc*'
+.PP
+\"---------------------------------------------------------------------------
+\"-----------------------
+.SH BACKGROUND INFORMATION
+.\"-----------------------
+.SS tapes
+.\"-----------
+A tape device handles all I/O (read, write, seek) in units of
+.IR "tape records".
+The bigger a tape record, the more effective usually is
+the access (and the less gaps are on QIC-tapes).
+However, normally a program will only read or write complete tape records.
+
+Normal tape drives allow to seek only relative to the current
+position. However, some newer SCSI-2 tapes, i.e. DAT,
+conforming to the DDS standard,
+keep track of the absolute position on the tape by inserting the
+tape record number inside each track.
+This number can be read while
+the fast seek is performed.
+
+The
+.B tar(1)
+program uses a slightly different terminology.
+It calls
+.IR "tape blocks"
+what normally is called
+.IR "tape records" .
+In the following sections we use the tar terminology
+to avoid confusion.
+.SS tar
+.\"-----------
+The unit inside a
+.B tar
+archive is a
+.I tar record
+with a fixed length of 512 bytes. Every file, directory or soft link
+will occupy at least one tar record of information about
+pathname, permission information and so on called header record.
+The data of each file is stored in additional tar records directly after
+the header record of that file.
+.PP
+tar reports the
+.I tar record number
+of every header record in the archive with its -R option.
+tar counts the records continuously,
+starting with
+.B 0
+(if invoked as tar -tR) or with
+.B 1
+(if invoked as tar -cR).
+.PP
+tar handles multiple records as a
+.IR "tar block" ,
+mainly to make the access of tapes (or disks) more efficient (and save
+tape space of QIC-tapes).
+tar only writes and reads full blocks to or from an archive.
+The -b option of tar controls, how many records are in
+one block. The default number of records per block is
+.BR 20 .
+This number is usually called the
+.IR "tar block size" .
+However, this term is a little bit confusing, since
+it does not mean the number of bytes in a block.
+Thus a perhaps better name would be the
+.IR "tar blocking factor" .
+
+.SS tar on tapes
+.\"-----------
+tar writes or reads its archive to or from tape in units of tar
+blocks.
+As stated above, only a complete tape block may be transferred to/from
+tape. To extract a specific tar block from tape, one has to
+read an entire tape block into a buffer and extract
+the specified tar record from the buffer manually.
+If you would like to read a tar record with a given number,
+you have to know the number of the first tape block of the archive
+and the tar block size to compute the number of the tape block witch
+contains the tar record to read.
+If the tar archive is the first file on the tape, the
+.I tape block number
+is the equal to the
+.IR "tar block number" .
+.PP
+.B Example:
+A file with the tar record number 1234 (records start with 0)
+may be found in a tape tar archive, written with a
+blocking factor of 20.
+It may be found in the tar block with the number
+.RS 7
+ blk = (int) 1234/20 = (int) 61.7 = 61
+.RE
+which is also the tape block number.
+The requested file is within this tar block at the record offset
+.RS 7
+ rec = 1234-(61*20) = 14
+.RE
+in 512 byte units.
+.PP
+If a current archive is not the first archive on the tape, then
+the number of
+.I tape blocks
+of all previous archives has to be
+added to the block number computed above,
+to get the
+.IR "current tape block number" .
+The number of previous tape records
+should be obtained from DDS devices
+when the tape is positioned
+at the beginning of the current archive (use
+.B mt-dds
+without arguments for example).
+.PP
+.B Example:
+Assuming the archive in the above example to be the second file
+on a tape, and the archive starts at tape block 20222.
+Then we will find our file with tar record number 1234
+in the tape block
+.RS 7
+ tblk = 20222 + (int) 1234/20 = 20283
+.RE
+on the tape.
+The record offset inside the tape block will be the same as above.
+
+\"---------------------------------------------------------------------------
+.SH WARNING
+This program can only read records (tar is calling them tape blocks)
+up to 32 kbytes due to the limitations of the Linux device driver.
+The extracted archive is written to stdout with a
+block size of 512 bytes.
+
+.SH ENVIRONMENT
+The environment variable
+.B TAPE
+overrides the default tape device /dev/tape.
+The variable
+.B DDS2TAR cat be used to give some options, e.g.
+.B --compress, -z, -s # , -b #.
+
+.SH "SEE ALSO"
+dds2index(1), mt(1), mt-dds(1), tar(1)
+
+.SH HISTORY
+This program was created to use the fast seek operation of my DAT
+streamer. The tapes are called dds (digital data storage).
+Since the program will write a tar archive to stdout,
+I called this program
+.BR dds2tar .
+If I created the index file, I'm now
+able to restore a file of 1MB within one minute even if the tape
+contains more than 2GB of data.
+
+Thanks to Andreas (Andreas_Bagge@h2.maus.de), who has written a nice
+manual page for the overloaded version 1.1.3 of the program dds2tar
+(I added too much features ... )
+His manual page for dds2tar-1.1.3 gave me the idea how to split the
+program dds2tar into the peaces dds2tar, dds2index and mt-dds.
+Additionally his manual page was the starting point for this page.
+
+Since the version 2.2 has a very robust algorithm to read the index file
+and the ability of pattern matching, a lot of options where obsolete
+and has been deleted. I tried to make dds2tar as simple I can.
+
+.SH AUTHOR
+J"org Weule (weule@cs.uni-duesseldorf.de), Phone +49 211 751409.
+This software is available at
+ftp.uni-duesseldorf.de:/pub/unix/apollo and
+sunsite.unc.edu:/pub/Linux/system/Backup
+
--- /dev/null
+%!PS-Adobe-3.0
+%%Creator: groff version 1.10
+%%CreationDate: Mon Feb 2 16:42:11 1998
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.10 0
+%%Pages: 4
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.10 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/MANUAL{
+statusdict begin/manualfeed true store end
+}bind def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72
+def/PL 841.89 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron
+/Zcaron/scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent
+/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen
+/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon
+/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
+/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex
+/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y
+/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft
+/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl
+/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen
+/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft
+/logicalnot/minus/registered/macron/degree/plusminus/twosuperior
+/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior
+/ordmasculine/guilsinglright/onequarter/onehalf/threequarters
+/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE
+/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
+/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn
+/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla
+/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
+/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash
+/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def
+/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0/Times-Bold RE
+/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 371.08(dds2tar\(1L\) dds2tar\(1L\))72 48 R/F1 9
+/Times-Bold@0 SF -.18(NA)72 84 S(ME).18 E F0(dds2tar \255 tool for f)108
+96 Q(ast tape access)-.1 E F1(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0 SF
+(dds2tar)108 124.8 Q F0([)2.5 E F2(-f)2.5 E/F3 10/Times-Italic@0 SF(de)
+2.5 E(vice)-.15 E F0 2.5(][)2.5 G F2(-t)A F3(inde)2.5 E(x\214le)-.2 E F0
+2.5(][)2.5 G(options])-2.5 E F3(string ...)2.5 E F1(DESCRIPTION)72 146.4
+Q F2(dds2tar)108 158.4 Q F0 .902(uses an inde)3.402 F 3.402(xt)-.15 G
+3.402<6f8c>-3.402 G .902(nd the \214les with record seek \(a f)-3.402 F
+.901(ast operation of D)-.1 F 3.121 -1.11(AT d)-.4 H -.25(ev)1.11 G
+3.401(ices\). Since).25 F .901(the \214le)3.401 F .789
+(structure of the tape archi)108 170.4 R -.15(ve)-.25 G 3.289(si).15 G
+3.289(su)-3.289 G .789(sed to e)-3.289 F .789
+(xtract the \214les, the archi)-.15 F 1.09 -.15(ve h)-.25 H .79
+(as to be created by).15 F F2(tar)3.29 E F0 3.29(,c)C(ompressed)-3.29 E
+.546(only by \(the transparent signal processor of\) the de)108 182.4 R
+3.045(vice. So)-.25 F .545(you can step through the archi)3.045 F .845
+-.15(ve ve)-.25 H .545(ry quickly).15 F .372(and e)108 194.4 R .372
+(xtract \214les.)-.15 F .372(The inde)5.372 F 2.872(xm)-.15 G .372
+(ay be created using)-2.872 F F2(dds2index)2.872 E F0(or)2.872 E F2(tar)
+2.872 E F0 .372(-vRt and is normally stored as a \214le on)B
+(your hard disk.)108 206.4 Q 2.549(At)108 223.2 S .049(ar archi)-2.549 F
+.349 -.15(ve i)-.25 H 2.549(sas).15 G .049
+(equence of blocks \(e.g. 10240 bytes by def)-2.549 F .049
+(ault\), each containing the same number \(20 by)-.1 F(def)108 235.2 Q
+.755(ault\) of records, 512 byte each.)-.1 F F2(dds2tar)5.755 E F0 .755
+(reads the tape and writes the tar records of the speci\214ed \214les)
+3.255 F 1.721(\(that means the header record and the data records of ea\
+ch selected \214le\) to stdout.)108 247.2 R -1.1(Yo)6.721 G 4.221(um)1.1
+G 1.721(ay pipe the)-4.221 F F2(dds2tar)108 259.2 Q F0 1.782
+(output to the stdin of)4.282 F F3 1.783(tar -xvvf -)4.283 F F0 1.783
+(to restore the \214les to your disk.)4.283 F(\(See)6.783 E F2(EXAMPLES)
+4.283 E F0(belo)4.283 E -.65(w.)-.25 G(\)).65 E(Before a \214le is e)108
+271.2 Q(xtracted, the records of parent directories of the \214le are a\
+lso written to stdout.)-.15 E .129(The inde)108 288 R 2.629(xo)-.15 G
+2.628(ft)-2.629 G .128(he archi)-2.628 F .428 -.15(ve s)-.25 H .128(hou\
+ld contain enough information to compute the number of the block contai\
+ning).15 F .334(the header of each selected \214le.)108 300 R F2
+(dds2index)5.335 E F0 .335(will gi)2.835 F .635 -.15(ve s)-.25 H .335
+(uch a table,).15 F F2 .335(tar -Rvt)2.835 F F0 .335
+(e.g. will not \(only record num-)2.835 F .104(bers are listed\).)108
+312 R 2.604(Ap)5.104 G .104(atch for)-2.604 F F2 .103(GNU tar)2.603 F
+(-1.12)-.37 E F0 .103(is a)2.603 F -.25(va)-.2 G .103
+(ilable, adding the option).25 F F2(--r)2.603 E(ecord-\214le.)-.18 E F0
+(Alternati)5.103 E -.15(ve)-.25 G .103(ly there).15 F
+(are some tricks to get the missing information.)108 324 Q .455
+(The strings are re)108 340.8 R .455(gular e)-.15 F .455
+(xpressions to select the \214les.)-.15 F .456
+(The matching algorithm is the one from GNU tar)5.456 F 2.956(.I)-.55 G
+(f)-2.956 E .274(the option)108 352.8 R F2(-l)2.774 E F0 .274(is gi)
+2.774 F -.15(ve)-.25 G .274
+(n, the matched \214le names are printed to stdout \(Y).15 F .273
+(ou may not pipe this list of pathnames)-1.1 F(to tar!\).)108 364.8 Q
+.726(The def)108 381.6 R .726(ault de)-.1 F .726(vice is)-.25 F F3(/de)
+3.226 E(v/rmt0)-.15 E F0 3.226(,w).47 G .726(hich may be o)-3.226 F -.15
+(ve)-.15 G .726(rridden with the en).15 F .726(vironment v)-.4 F
+(ariable)-.25 E F2 -.9(TA)3.226 G(PE).9 E F0 3.226(,w)C .726(hich in)
+-3.226 F(turn may be o)108 393.6 Q -.15(ve)-.15 G(rridden with the).15 E
+F2(-f)2.5 E F3(de)2.85 E(vice)-.15 E F0(option. The de)2.5 E
+(vice must be a SCSI tape de)-.25 E(vice.)-.25 E F1(OPTIONS)72 410.4 Q
+F2(-f)108 422.4 Q F3(de)2.85 E(vice\214le)-.15 E F0(De)2.5 E
+(vice of the tape archi)-.25 E -.15(ve)-.25 G 2.5(.M).15 G
+(ust be a SCSI tape de)-2.5 E(vice.)-.25 E F2(-t)108 439.2 Q F3(inde)
+2.51 E(x\214le)-.2 E F0(Speci\214es the inde)144 451.2 Q 2.5<788c>-.15 G
+(le \(def)-2.5 E(ault is stdin\).)-.1 E F2(-s #)108 468 Q F0 .01
+(Set the number of the \214rst tape block of the archi)21.28 F -.15(ve)
+-.25 G 2.51(.T).15 G .01(his option is useful only if the inde)-2.51 F
+2.51<788c>-.15 G .01(le con-)-2.51 F .995(tains the v)144 480 R .995
+(erbose output of)-.15 F F2 .995(tar -Rvt.)3.495 F F0(An)5.996 E 3.496
+(yi)-.15 G .996(nformation about the \214rst block inside the inde)
+-3.496 F 3.496<788c>-.15 G(le)-3.496 E .384(will be o)144 492 R -.15(ve)
+-.15 G .384(rridden by this option.).15 F .384(If no information is a)
+5.384 F -.25(va)-.2 G .384(ilable, the archi).25 F .684 -.15(ve h)-.25 H
+.384(as to be the \214rst \214le).15 F(of the tape. If you ha)144 504 Q
+.3 -.15(ve p)-.2 H
+(ositioned your tape at the \214rst block of the archi).15 E -.15(ve)
+-.25 G 2.5(,y).15 G(ou can use)-2.5 E F2
+(dds2tar `mt-dds` -t index ... | tar -f - ...)144 520.8 Q F0
+(to complete the information of the output of)144 537.6 Q F2(tar -Rvt)
+2.5 E F0(stored in the inde)2.5 E 2.5<788c>-.15 G(le.)-2.5 E F2(-b #)108
+554.4 Q F0 .639(Set the blocksize of the archi)19.61 F .939 -.15(ve \()
+-.25 H .64(tar -b #\). This option is useful only if the inde).15 F 3.14
+<788c>-.15 G .64(le contains the)-3.14 F -.15(ve)144 566.4 S .183
+(rbose output of tar \(or if you ha).15 F .483 -.15(ve p)-.2 H .183
+(roblems with the size of the internal b).15 F(uf)-.2 E .182
+(fer of dds2tar\).)-.25 F(An)5.182 E(y)-.15 E .209
+(information about the blocksize inside the inde)144 578.4 R 2.709<788c>
+-.15 G .209(le will be o)-2.709 F -.15(ve)-.15 G .21
+(rridden by this option.).15 F .21(If no infor)5.21 F(-)-.2 E
+(mation is a)144 590.4 Q -.25(va)-.2 G(ilable, the def).25 E
+(ault blocksize of tar is used.)-.1 E F2(-z)108 607.2 Q F0(The inde)
+28.23 E 2.5<788c>-.15 G
+(le should be read and stored in compressed mode.)-2.5 E F1(OPTIONS y)72
+624 Q(ou didn't r)-.225 E(eally need)-.162 E F2(--z, --no-compr)108 636
+Q(ess)-.18 E F0(Don')144 648 Q 2.5<748c>-.18 G(lter the archi)-2.5 E .3
+-.15(ve \214)-.25 H(le through gzip.).15 E F2(-q, --quick)108 664.8 Q F0
+(Don')144 676.8 Q 3.205(te)-.18 G .705
+(xtract the parent directories of the selected objects from tape.)-3.355
+F F2(--body)5.704 E F0 .704(Write only the \214rst)3.204 F .161
+(selected \214le to stdout. This is useful if you w)144 688.8 R .161
+(ant to read a \214le or e)-.1 F .161(xtract an archi)-.15 F .461 -.15
+(ve w)-.25 H .161(hich is part of).15 F(the current archi)144 700.8 Q
+-.15(ve)-.25 G(.).15 E 220.25(2.3 1)299.75 768 R EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 371.08(dds2tar\(1L\) dds2tar\(1L\))72 48 R/F1 10
+/Times-Bold@0 SF(-v)108 84 Q F0(,)A F1(--v)A(erbose)-.1 E F0 -.15(ve)144
+96 S(rbose mode.).15 E F1(--hash-mode)108 112.8 Q F0
+(Print a hash sign for each MB.)144 124.8 Q F1(-V)108 141.6 Q F0(,)A F1
+(--v)A(ersion)-.1 E F0(Print only the V)144 153.6 Q
+(ersion Number to stderr)-1.11 E(.)-.55 E F1(-l)108 170.4 Q F0(Don')
+29.89 E 3.226(ta)-.18 G .726(ccess the tape b)-3.226 F .726
+(ut print the \214le names to stdout.)-.2 F -1.1(Yo)5.725 G 3.225(um)1.1
+G .725(ay not pipe this list of pathnames)-3.225 F(into tar)144 182.4 Q
+(.)-.55 E F1(--extract)108 199.2 Q F0 .22
+(The stdout is closed and opened by a pipe to the command)144 211.2 R F1
+.221(tar -fxb - 1 .)2.721 F F0 -1.1(Yo)5.221 G 2.721(um)1.1 G .221
+(ay \214nd this option)-2.721 F(con)144 223.2 Q -.15(ve)-.4 G
+(nient, I lik).15 E 2.5(et)-.1 G 2.5(op)-2.5 G
+(ipe the output to tar by hand.)-2.5 E/F2 9/Times-Bold@0 SF(EXAMPLES)72
+240 Q F0(Example of)108 252 Q F1(getting the index)2.5 E F0
+(from the def)2.5 E(ault tape /de)-.1 E
+(v/rmt0 and storing it in \214le archi)-.25 E -.15(ve)-.25 G(.idx:).15 E
+(dds2inde)144 268.8 Q 2.5(x-)-.15 G 2.5(ta)-2.5 G(rchi)-2.5 E -.15(ve)
+-.25 G(.idx).15 E(Alternati)108 285.6 Q -.15(ve)-.25 G .271
+(ly you can use a patched v).15 F .271(ersion of tar to create an inde)
+-.15 F 2.771<788c>-.15 G 2.771(le. W)-2.771 F .271
+(ith the patch you can direct the)-.4 F .801(errors and w)108 297.6 R
+.801(arning to stdout and the inde)-.1 F 3.301(xi)-.15 G .802
+(nformation including information about the blocksize and the)-3.301 F
+(number of the \214rst block to a \214le:)108 309.6 Q
+(tar -t --record-\214le archi)144 326.4 Q -.15(ve)-.25 G(.idx).15 E .385
+(If the archi)108 343.2 R .685 -.15(ve i)-.25 H 2.885(st).15 G .384
+(he \214rst \214le of the tape and the blocksize is the def)-2.885 F
+.384(ault of 20, you can use the v)-.1 F .384(erbose out-)-.15 F
+(put of tar \(-Rv\) as an inde)108 355.2 Q 2.5<788c>-.15 G(le.)-2.5 E
+(tar -t -v -R | tee archi)144 372 Q -.15(ve)-.25 G(.idx).15 E .203
+(If the archi)108 388.8 R .503 -.15(ve i)-.25 H 2.703(sn).15 G .204(ot \
+the \214rst \214le of the tape, you can store all the necessary informa\
+tion inside the inde)-2.703 F 2.704<788c>-.15 G(le)-2.704 E
+(with the use of)108 400.8 Q F1(mt-dds)2.5 E F0(and)2.5 E F1(tar)2.5 E
+F0(:)2.5 E(mt asf ...)144 417.6 Q(mt-dds tell > archi)144 429.6 Q -.15
+(ve)-.25 G(.idx).15 E(tar -tvR >>archi)144 441.6 Q -.15(ve)-.25 G(.idx)
+.15 E .057(Example of)108 458.4 R F1 .057(using dds2tar)2.557 F F0 .057
+(to e)2.557 F .056(xtract the gnu library \(all \214les containing the \
+string "glibc" in \214lename\) from)-.15 F(the def)108 470.4 Q
+(ault tape /de)-.1 E(v/rmt0, using the pre)-.25 E(viously stored inde)
+-.25 E 2.5<788c>-.15 G(le archi)-2.5 E -.15(ve)-.25 G(.idx:).15 E
+(dds2tar -t archi)144 487.2 Q -.15(ve)-.25 G
+(.idx '*glibc*' | tar xvvf -).15 E 2.206 -.8(To s)108 504 T .606
+(ee in adv).8 F .607(ance what w)-.25 F .607(ould happen in the pre)-.1
+F .607(vious command without actually writing an)-.25 F .607
+(ything to your)-.15 F(disk, you may use:)108 516 Q(dds2tar -t archi)144
+532.8 Q -.15(ve)-.25 G(.idx '*glibc*' | tar tvvf -).15 E
+(Example of checking the matches. Y)108 549.6 Q(ou may try:)-1.1 E
+(dds2tar -t archi)144 566.4 Q -.15(ve)-.25 G(.idx -l '*glibc*').15 E F2
+-.27(BA)72 612 S(CKGR)-.225 E(OUND INFORMA)-.27 E(TION)-.855 E F1(tapes)
+87 624 Q F0 2.517(At)108 636 S .017(ape de)-2.517 F .017
+(vice handles all I/O \(read, write, seek\) in units of)-.25 F/F3 10
+/Times-Italic@0 SF .016(tape r)2.516 F(ecor)-.37 E(ds)-.37 E F0 5.016
+(.T).27 G .016(he bigger a tape record, the more)-5.016 F(ef)108 648 Q
+(fecti)-.25 E .362 -.15(ve u)-.25 H .063
+(sually is the access \(and the less g).15 F .063
+(aps are on QIC-tapes\).)-.05 F(Ho)5.063 E(we)-.25 E -.15(ve)-.25 G .863
+-.4(r, n).15 H .063(ormally a program will only).4 F
+(read or write complete tape records.)108 660 Q .433(Normal tape dri)108
+684 R -.15(ve)-.25 G 2.933(sa).15 G(llo)-2.933 E 2.933(wt)-.25 G 2.933
+(os)-2.933 G .433(eek only relati)-2.933 F .733 -.15(ve t)-.25 H 2.932
+(ot).15 G .432(he current position. Ho)-2.932 F(we)-.25 E -.15(ve)-.25 G
+1.232 -.4(r, s).15 H .432(ome ne).4 F .432(wer SCSI-2 tapes,)-.25 F .553
+(i.e. D)108 696 R -1.02 -1.11(AT ,)-.4 H .553
+(conforming to the DDS standard, k)4.163 F .554
+(eep track of the absolute position on the tape by inserting the)-.1 F
+(tape record number inside each track.)108 708 Q
+(This number can be read while the f)5 E(ast seek is performed.)-.1 E
+220.25(2.3 2)299.75 768 R EP
+%%Page: 3 3
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 371.08(dds2tar\(1L\) dds2tar\(1L\))72 48 R(The)
+108 84 Q/F1 10/Times-Bold@0 SF(tar\(1\))3.045 E F0 .545
+(program uses a slightly dif)3.045 F .545(ferent terminology)-.25 F
+5.545(.I)-.65 G 3.045(tc)-5.545 G(alls)-3.045 E/F2 10/Times-Italic@0 SF
+.545(tape bloc)3.045 F(ks)-.2 E F0 .545(what normally is called)3.045 F
+F2(tape)3.045 E -.37(re)108 96 S(cor).37 E(ds)-.37 E F0 5(.I).27 G 2.5
+(nt)-5 G(he follo)-2.5 E(wing sections we use the tar terminology to a)
+-.25 E -.2(vo)-.2 G(id confusion.).2 E F1(tar)87 112.8 Q F0 .814
+(The unit inside a)108 124.8 R F1(tar)3.314 E F0(archi)3.314 E 1.115
+-.15(ve i)-.25 H 3.315(sa).15 G F2 .815(tar r)B(ecor)-.37 E(d)-.37 E F0
+.815(with a \214x)3.315 F .815(ed length of 512 bytes. Ev)-.15 F .815
+(ery \214le, directory or soft)-.15 F .777(link will occup)108 136.8 R
+3.277(ya)-.1 G 3.277(tl)-3.277 G .777(east one tar record of informatio\
+n about pathname, permission information and so on)-3.277 F .118
+(called header record.)108 148.8 R .119(The data of each \214le is stor\
+ed in additional tar records directly after the header record)5.119 F
+(of that \214le.)108 160.8 Q .937(tar reports the)108 177.6 R F2 .937
+(tar r)3.437 F(ecor)-.37 E 3.437(dn)-.37 G(umber)-3.437 E F0 .936(of e)
+3.437 F -.15(ve)-.25 G .936(ry header record in the archi).15 F 1.236
+-.15(ve w)-.25 H .936(ith its -R option.).15 F .936(tar counts the)5.936
+F(records continuously)108 189.6 Q 2.5(,s)-.65 G(tarting with)-2.5 E F1
+(0)2.5 E F0(\(if in)2.5 E -.2(vo)-.4 G -.1(ke).2 G 2.5(da).1 G 2.5(st)
+-2.5 G(ar -tR\) or with)-2.5 E F1(1)2.5 E F0(\(if in)2.5 E -.2(vo)-.4 G
+-.1(ke).2 G 2.5(da).1 G 2.5(st)-2.5 G(ar -cR\).)-2.5 E .074
+(tar handles multiple records as a)108 206.4 R F2 .074(tar bloc)2.574 F
+(k)-.2 E F0 2.574(,m).67 G .074(ainly to mak)-2.574 F 2.574(et)-.1 G
+.074(he access of tapes \(or disks\) more ef)-2.574 F .075
+(\214cient \(and)-.25 F(sa)108 218.4 Q .443 -.15(ve t)-.2 H .143
+(ape space of QIC-tapes\).).15 F .142
+(tar only writes and reads full blocks to or from an archi)5.143 F -.15
+(ve)-.25 G 5.142(.T).15 G .142(he -b option of)-5.142 F .238
+(tar controls, ho)108 230.4 R 2.738(wm)-.25 G(an)-2.738 E 2.738(yr)-.15
+G .238(ecords are in one block. The def)-2.738 F .239
+(ault number of records per block is)-.1 F F1(20)2.739 E F0 5.239(.T)C
+.239(his num-)-5.239 F .628(ber is usually called the)108 242.4 R F2
+.628(tar bloc)3.128 F 3.128(ks)-.2 G(ize)-3.128 E F0 5.628(.H).18 G -.25
+(ow)-5.628 G -2.15 -.25(ev e).25 H 1.428 -.4(r, t).25 H .627
+(his term is a little bit confusing, since it does not mean).4 F
+(the number of bytes in a block.)108 254.4 Q
+(Thus a perhaps better name w)5 E(ould be the)-.1 E F2(tar bloc)2.5 E
+(king factor)-.2 E F0(.).73 E F1(tar on tapes)87 283.2 Q F0 .529
+(tar writes or reads its archi)108 295.2 R .829 -.15(ve t)-.25 H 3.029
+(oo).15 G 3.029(rf)-3.029 G .529(rom tape in units of tar blocks.)-3.029
+F .529(As stated abo)5.529 F -.15(ve)-.15 G 3.029(,o).15 G .529
+(nly a complete tape)-3.029 F .629
+(block may be transferred to/from tape.)108 307.2 R 2.229 -.8(To e)5.629
+H .629
+(xtract a speci\214c tar block from tape, one has to read an entire).65
+F .517(tape block into a b)108 319.2 R(uf)-.2 E .517(fer and e)-.25 F
+.517(xtract the speci\214ed tar record from the b)-.15 F(uf)-.2 E .518
+(fer manually)-.25 F 5.518(.I)-.65 G 3.018(fy)-5.518 G .518(ou w)-3.018
+F .518(ould lik)-.1 F 3.018(et)-.1 G(o)-3.018 E .688
+(read a tar record with a gi)108 331.2 R -.15(ve)-.25 G 3.188(nn).15 G
+(umber)-3.188 E 3.188(,y)-.4 G .688(ou ha)-3.188 F .988 -.15(ve t)-.2 H
+3.188(ok).15 G(no)-3.188 E 3.188(wt)-.25 G .688
+(he number of the \214rst tape block of the archi)-3.188 F -.15(ve)-.25
+G .351(and the tar block size to compute the number of the tape block w\
+itch contains the tar record to read.)108 343.2 R .351(If the)5.351 F
+(tar archi)108 355.2 Q .3 -.15(ve i)-.25 H 2.5(st).15 G
+(he \214rst \214le on the tape, the)-2.5 E F2(tape bloc)2.5 E 2.5(kn)-.2
+G(umber)-2.5 E F0(is the equal to the)2.5 E F2(tar bloc)2.5 E 2.5(kn)-.2
+G(umber)-2.5 E F0(.).73 E F1(Example:)108 372 Q F0 2.861<418c>2.861 G
+.36(le with the tar record number 1234 \(records start with 0\) may be \
+found in a tape tar archi)-2.861 F -.15(ve)-.25 G(,).15 E
+(written with a blocking f)108 384 Q(actor of 20.)-.1 E
+(It may be found in the tar block with the number)5 E
+(blk = \(int\) 1234/20 = \(int\) 61.7 = 61)165.5 396 Q
+(which is also the tape block number)108 408 Q 5(.T)-.55 G
+(he requested \214le is within this tar block at the record of)-5 E
+(fset)-.25 E(rec = 1234-\(61*20\) = 14)165.5 420 Q(in 512 byte units.)
+108 432 Q 1.625(If a current archi)108 448.8 R 1.925 -.15(ve i)-.25 H
+4.125(sn).15 G 1.625(ot the \214rst archi)-4.125 F 1.925 -.15(ve o)-.25
+H 4.125(nt).15 G 1.625(he tape, then the number of)-4.125 F F2 1.625
+(tape bloc)4.125 F(ks)-.2 E F0 1.625(of all pre)4.125 F(vious)-.25 E
+(archi)108 460.8 Q -.15(ve)-.25 G 3.032(sh).15 G .531
+(as to be added to the block number computed abo)-3.032 F -.15(ve)-.15 G
+3.031(,t).15 G 3.031(og)-3.031 G .531(et the)-3.031 F F2(curr)3.031 E
+.531(ent tape bloc)-.37 F 3.031(kn)-.2 G(umber)-3.031 E F0 5.531(.T).73
+G(he)-5.531 E .722(number of pre)108 472.8 R .723
+(vious tape records should be obtained from DDS de)-.25 F .723
+(vices when the tape is positioned at the)-.25 F(be)108 484.8 Q
+(ginning of the current archi)-.15 E .3 -.15(ve \()-.25 H(use).15 E F1
+(mt-dds)2.5 E F0(without ar)2.5 E(guments for e)-.18 E(xample\).)-.15 E
+F1(Example:)108 501.6 Q F0 .205(Assuming the archi)2.705 F .505 -.15
+(ve i)-.25 H 2.704(nt).15 G .204(he abo)-2.704 F .504 -.15(ve ex)-.15 H
+.204(ample to be the second \214le on a tape, and the archi).15 F .504
+-.15(ve s)-.25 H(tarts).15 E(at tape block 20222.)108 513.6 Q(Then we w\
+ill \214nd our \214le with tar record number 1234 in the tape block)5 E
+(tblk = 20222 + \(int\) 1234/20 = 20283)165.5 525.6 Q(on the tape.)108
+537.6 Q(The record of)5 E
+(fset inside the tape block will be the same as abo)-.25 E -.15(ve)-.15
+G(.).15 E/F3 9/Times-Bold@0 SF -1.08(WA)72 578.4 S(RNING)1.08 E F0 .503
+(This program can only read records \(tar is calling them tape blocks\)\
+ up to 32 kbytes due to the limitations)108 590.4 R(of the Linux de)108
+602.4 Q(vice dri)-.25 E -.15(ve)-.25 G 3.6 -.55(r. T).15 H(he e).55 E
+(xtracted archi)-.15 E .3 -.15(ve i)-.25 H 2.5(sw).15 G
+(ritten to stdout with a block size of 512 bytes.)-2.5 E F3(ENVIR)72
+631.2 Q(ONMENT)-.27 E F0 .587(The en)108 643.2 R .587(vironment v)-.4 F
+(ariable)-.25 E F1 -.9(TA)3.087 G(PE).9 E F0 -.15(ove)3.087 G .587
+(rrides the def).15 F .587(ault tape de)-.1 F .587(vice /de)-.25 F 3.087
+(v/rmt0. The)-.25 F -.25(va)3.087 G(riable).25 E F1(DDS2T)3.087 E .586
+(AR cat)-.9 F(be used to gi)108 655.2 Q .2 -.1(ve s)-.1 H
+(ome options, e.g).1 E 5(.-)-.15 G(-compr)-5 E(ess, -z, -s # , -b #.)
+-.18 E F3(SEE ALSO)72 684 Q F0(dds2inde)108 696 Q
+(x\(1\), mt\(1\), mt-dds\(1\), tar\(1\))-.15 E 220.25(2.3 3)299.75 768 R
+EP
+%%Page: 4 4
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 371.08(dds2tar\(1L\) dds2tar\(1L\))72 48 R/F1 9
+/Times-Bold@0 SF(HIST)72 84 Q(OR)-.162 E(Y)-.315 E F0 .025
+(This program w)108 96 R .025(as created to use the f)-.1 F .025
+(ast seek operation of my D)-.1 F 2.245 -1.11(AT s)-.4 H(treamer)1.11 E
+2.525(.T)-.55 G .026(he tapes are called dds \(digi-)-2.525 F .745
+(tal data storage\).)108 108 R .744
+(Since the program will write a tar archi)5.745 F 1.044 -.15(ve t)-.25 H
+3.244(os).15 G .744(tdout, I called this program)-3.244 F/F2 10
+/Times-Bold@0 SF(dds2tar)3.244 E F0 5.744(.I)C 3.244(fI)-5.744 G .99
+(created the inde)108 120 R 3.49<788c>-.15 G .99(le, I'm no)-3.49 F 3.49
+(wa)-.25 G .991(ble to restore a \214le of 1MB within one minute e)-3.49
+F -.15(ve)-.25 G 3.491(ni).15 G 3.491(ft)-3.491 G .991(he tape contains)
+-3.491 F(more than 2GB of data.)108 132 Q .374(Thanks to Andreas \(Andr\
+eas_Bagge@h2.maus.de\), who has written a nice manual page for the o)108
+156 R -.15(ve)-.15 G(rloaded).15 E -.15(ve)108 168 S .05(rsion 1.1.3 of\
+ the program dds2tar \(I added too much features ... \) His manual page\
+ for dds2tar).15 F .05(-1.1.3 g)-.2 F -2.25 -.2(av e)-.05 H .542
+(me the idea ho)108 180 R 3.042(wt)-.25 G 3.042(os)-3.042 G .542
+(plit the program dds2tar into the peaces dds2tar)-3.042 F 3.042(,d)-.4
+G(ds2inde)-3.042 E 3.042(xa)-.15 G .541(nd mt-dds.)-3.042 F
+(Additionally)5.541 E(his manual page w)108 192 Q
+(as the starting point for this page.)-.1 E .107(Since the v)108 216 R
+.107(ersion 2.2 has a v)-.15 F .107(ery rob)-.15 F .107
+(ust algorithm to read the inde)-.2 F 2.608<788c>-.15 G .108
+(le and the ability of pattern matching, a)-2.608 F
+(lot of options where obsolete and has been deleted. I tried to mak)108
+228 Q 2.5(ed)-.1 G(ds2tar as simple I can.)-2.5 E F1 -.45(AU)72 256.8 S
+(THOR).45 E F0(J"or)108 268.8 Q 3.029(gW)-.18 G .529
+(eule \(weule@cs.uni-duesseldorf.de\), Phone +49 211 751409.)-3.829 F
+.528(This softw)5.528 F .528(are is a)-.1 F -.25(va)-.2 G .528
+(ilable at ftp.uni-).25 F(duesseldorf.de:/pub/unix/apollo and sunsite.u\
+nc.edu:/pub/Linux/system/Backup)108 280.8 Q 220.25(2.3 4)299.75 768 R EP
+%%Trailer
+end
+%%EOF
--- /dev/null
+
+/*
+ * This file is part of dds2tar.
+ * Copyright by J"org Weule
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mtio.h>
+#include <unistd.h>
+#include <string.h>
+#include "dds2tar.h"
+#include "dds_tape.h"
+
+int dds_is_tar_header_record(tar_record*const ptr){
+ int i;
+ unsigned int n = 0;
+ unsigned char *p = (char*)ptr ;
+
+ for (i = 0; i < 148; i++)
+ n += p[i];
+ for (i = 0; i < 8; i++)
+ n += ' ';
+ for (i = 156; i < 512; i++)
+ n += p[i];
+ sscanf(p + 148, "%8o", &i);
+ if ( n != ((int)' ') * 8 ){
+ if ( i == 0 ) {
+ sprintf(p+148 , "%o", n );
+ } else
+ if ( i != n ) return 0;
+ sscanf(ptr->hdr.size,"%o",&i);
+ i += 512 + 511 ;
+ i >>= 9 ;
+ } else i=1 ;
+ return i;
+}
+
+
--- /dev/null
+
+/*
+ * This file is part of dds2tar.
+ * Copyright by J"org Weule
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mtio.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * fnmatch() and FNM_LEADING_DIR
+ */
+#define _GNU_SOURCE 1
+#include <fnmatch.h>
+
+#include "dds2tar.h"
+#include "dds_tape.h"
+
+/*
+ * Compare two strings
+ *
+ */
+int dds_strcmp(const char*n1,const char*n2){
+ int i = 0 ;
+ int j = 0 ;
+ while ( 1 ){
+ while ( n1[i] == '\\' ) i++ ;
+ while ( n2[j] == '\\' ) j++ ;
+ if ( i > 90 || j > 90 || n1[i] == '\0' || n2[j] == '\0' )
+ return 0 ;
+ if ( n1[i] != n2[j] ) return 1 ;
+ i++ ;
+ j++ ;
+ }
+ return 0 ;
+}
+
+/*
+ * To count the number of blocks written, we use the variable nblocks.
+ */
+static int nblocks = 0;
+
+/*
+ * Fill the buffer 'cur_block' the block of the given number.
+ * first we check the block number of the copy that is hold inside the
+ * buffer cur_block.
+ */
+static int
+set_cur_block(int const sb)
+{
+ int n;
+
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+ fprintf(stderr, "set_cur_block(%d)\n", sb);
+#endif
+
+ if (sb != cur_blkno) {
+ /*
+ * We have to read the block.
+ */
+ next_blkno = dds_getpos(device);
+ /*
+ * next_blkno stores now the number of the next block of the
+ * tape.
+ */
+ n = sb - next_blkno;
+ /*
+ * In some cases reading is faster then seeking.
+ */
+ if ((n > 0) && (n < DONT_SKIP)) {
+ do {
+ dds_read_block();
+ } while ((--n) > 0);
+ }
+ /*
+ * Now we should be at the position.
+ */
+ n = sb - next_blkno;
+ if (n != 0) {
+ dds_seek(device, sb);
+ next_blkno = sb;
+ }
+ /*
+ * Now we read the block. cur_n == 0 indicates a filemark.
+ */
+ dds_read_block();
+ }
+ return 0;
+}
+
+/*
+ * procedure to extract the files from the specified area (sb:sr-eb:er).
+ * If area is of the form (sb:sr-0:0), the file at position (sb,sr) is
+ * extracted. The length of the file is read from the tar header record.
+ *
+ * If list_only is set to 1, only the name of the extraction is printed.
+ */
+static int
+extract(char const *const name, int const sb, int const sr)
+{
+
+ int cur_rec, n, size;
+ char *p;
+
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+ fprintf(stderr, "extract(%s,%d,%d)\n", name, sb, sr);
+#endif
+
+ /*
+ * Print only the name.
+ */
+ if (list_only == 1) {
+ printf("%7d%3d: %s\n", sb, sr, name);
+ return 0;
+ }
+ /*
+ * Print the filename and the location for verbose output.
+ */
+ if (verbose != 0) {
+ fprintf(stderr,
+ "dds2tar at rec %d: %7d%3d: %s\n",
+ nblocks, sb, sr, name);
+ }
+ /*
+ * Check the buffer for the right tape block.
+ */
+ set_cur_block(sb);
+
+ cur_rec = sr;
+ /*
+ * Check the header block.
+ * The Name field should contain the given name.
+ * The Program will stop if its not.
+ *
+ * Note that for links we can only compare the first
+ * characters, when the index contains somethins like
+ * 'linkname -> filename' (soft link) or
+ * 'linkname link to filename' (hard link)
+ * doesn't match 'linkname'.
+ */
+ p = (char*) (cur_block + cur_rec) ;
+ if ( dds_is_tar_header_record((tar_record*)p) == 0 ) {
+ fprintf(stderr,
+ " dds2tar: FATAL ERROR\n"
+ " dds2tar: header expected, not found\n"
+ );
+ if ( force_nochk == 0 ) exit(5);
+ }
+ if (name != NULL)
+ if ( ( (dds_strcmp(name, p)!=0 )
+ && (((tar_record*)p)->hdr.linkflag!='2')
+ && (((tar_record*)p)->hdr.linkflag!='1')
+ ) || ( strstr(name, p)!=name ) ) {
+ fprintf(stderr,
+ "dds2tar: FATAL ERROR\n"
+ "dds2tar: Looked for %s at %d %d\n"
+ "dds2tar: Could not find %s at %d %d.\n"
+ "dds2tar: Found %s\n"
+ "dds2tar: Link flag: %c\n"
+ "dds2tar: Is it the right tape?\n",
+ name, sb , sr ,
+ name, dds_getpos(device) - 1, cur_rec,p,
+ ((tar_record*)p)->hdr.linkflag);
+ if ( force_nochk == 0 ) exit(5);
+ }
+ /*
+ * First calculate the number of records of the object.
+ */
+ size = 0;
+ n = 1;
+
+ p = cur_block[cur_rec].hdr.size;
+ if (*p != '\0') {
+ sscanf(p, "%o", &size);
+ n = size;
+ n += 1023;
+ n >>= 9;
+ }
+ /*
+ * Now write the records to stdout.
+ */
+ if (verbose) {
+ fprintf(stderr,
+ "dd2tar: %s needs %d blocks\n", name, n);
+ }
+ if ( write_body == 1 ) {
+ cur_rec++;
+ while ((size > 0) && (cur_n > 0)) {
+ if (cur_rec >= cur_bs) {
+ dds_read_block();
+ cur_rec = 0;
+ }
+ write(1, cur_block + cur_rec, (size>=512)? 512:size );
+ size -= 512 ;
+ cur_rec++;
+ }
+ exit(0);
+ }
+ while ((n > 0) && (cur_n > 0)) {
+ if (cur_rec >= cur_bs) {
+ dds_read_block();
+ cur_rec = 0;
+ }
+ write(1, cur_block + cur_rec, 512);
+ nblocks++;
+ n--;
+ cur_rec++;
+ }
+ return 0;
+}
+
+#ifdef EXP_STUFF
+int
+extract_loc(char const *const *loc_list)
+{
+ int cur_rec ;
+
+ while (*loc_list != NULL) {
+ int eb, er, sb, sr;
+
+ sscanf(*loc_list, "%u:%u-%u:%u", &sb, &sr, &eb, &er);
+ set_cur_block(sb);
+ cur_rec = sr ;
+ while (cur_n > 0) {
+ int i;
+
+ if ((cur_n & 0x1ff) != 0) {
+ fprintf(stderr,
+ "tape record size (%d) is not a"
+ " multiple of tar records\n"
+ , cur_n
+ );
+ close(device);
+ exit(6);
+ }
+ i = cur_n >> 9;
+ if (cur_blkno == eb)
+ i = er;
+ while (cur_rec < i) {
+ write(1, cur_block + cur_rec++, 512);
+ nblocks++;
+ }
+ /*
+ * if eb==-1 extract until eof
+ */
+ if ((cur_rec == er && cur_blkno == eb))
+ break;
+ i = cur_blkno + 1;
+ cur_rec = 0;
+ if ((cur_rec == er && cur_blkno == eb))
+ break;
+ dds_read_block();
+ }
+ loc_list++;
+ }
+ return 0;
+}
+
+#endif
+
+/*
+ * Now we are scanning the table of contents (index file) and match the
+ * pathnames there with the given pattern. If a pattern matches, we
+ * extract the parent directories (dir_extract()) and the file.
+ */
+int
+dds_cmp(char const *const *const pattern_list)
+{
+ int i ;
+ char *fgets_return_value ;
+ char const *const *p;
+ int so = 0 ; /*scanoffset*/
+
+ /*
+ * To scan the line of the table of contents (index file)
+ * we need some variables.
+ */
+ char *name = NULL;
+ int blkno, recno, size;
+
+ /*
+ * List of directories entries.
+ */
+ struct dir_list {
+ char n[128-2*sizeof(int)]; /* name of the dir */
+ int b, r; /* block address */
+ }
+ *dl;
+ int de = 0; /* first empty list entry */
+
+ /*
+ * Format of the table of contents.
+ * dds2index --> tar_index_file == 0
+ * tar -Rvt --> tar_index_file == 1
+ */
+ int tar_index_file = 1;
+
+ /*
+ * Bug fix for tar. First record number found inside the
+ * table of contents (index file).
+ */
+ int tar_first_recno = -1;
+
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+ fprintf(stderr,"dds_cmp(%s ...)\n",*pattern_list);
+#endif
+
+
+ /*
+ * First we need some memory.
+ */
+ dl = malloc(sizeof (*dl) * 64);
+ if (dl == NULL) {
+ close(device);
+ fprintf(stderr, "dds2tar: no address space available\n");
+ exit(7);
+ }
+ memset(cur_line, 0, 1024);
+
+ /*
+ * Scan the table of conten|s (index file) until eof.
+ */
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+#endif
+ while (!feof(index_fp)) {
+ fgets_return_value = fgets(cur_line, MAXPATHLEN<<2, index_fp);
+ if ( fgets_return_value == NULL ) {
+ if ( feof(index_fp) ) {
+ break ;
+ } else {
+ perror("dds2tar");
+ exit(1);
+ }
+ }
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+ fputs(cur_line, stderr);
+#endif
+
+ /*
+ * Check for comment and empty lines.
+ */
+ if ((*cur_line == '#') ||
+ (*cur_line == ' ') ||
+ (*cur_line == '\0'))
+ continue;
+
+ /*
+ * Check the line for location information.
+ */
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+#endif
+ if (0 == rt_loc_line())
+ continue;
+
+ /*
+ * Check for the first line of the dds2index.
+ */
+ if ((0 == strcmp(cur_line, dds_headline))
+ || (0 == strcmp(cur_line, dds_old_headline))) {
+ tar_index_file = 0;
+ tar_n = buf_n ;
+ tar_bs = buf_n >> 9 ;
+ if ( vid != HP ) dds_set_bs(tar_n);
+ continue;
+ }
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+#endif
+
+ /*
+ * dds2index indicates eof with the string '-end-'.
+ * This line has to be processed in the normal way.
+ * We can stop now processing.
+ */
+ if ((*cur_line == '-') &&
+ (strncmp(cur_line, "-end-", 5) == 0)) {
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+#endif
+ break;
+ }
+
+ /*
+ * Scan the line of the index.
+ * Note: The index file of dds2index contains the magic string
+ * of the tar header, witch depends on the used tar version.
+ */
+ if (tar_index_file == 0) {
+ rt_line(&blkno, &recno, &size, &name);
+ } else {
+ /*
+ * check for record line
+ */
+ if ((0 != strncmp(cur_line, "rec", 3)) &&
+ (0 != strncmp(cur_line, "block", 5)))
+ continue;
+
+ /*
+ * cook the input line and delete all the quoted
+ * characters.
+ */
+ dds_unquote(cur_line);
+
+ /*
+ * Set scanoffset
+ */
+ so = (0 == strncmp(cur_line, "block", 5))? 2 : 0 ;
+
+ recno = atoi(cur_line + 4 + so );
+ /*
+ * tar-1.13 writes now the block number:
+ */
+ if ( so == 0 ){
+ int x ;
+ int n ;
+ char c;
+ if ( 2 == sscanf(
+ cur_line+16,"block %d%c%n",&x,&c,&n
+ ) && c == ':' ) {
+ so += n + 1 ;
+ recno = x ;
+#ifdef DDS_TRACE
+ fprintf(stderr,"Blocks found:%d\n",x);
+#endif
+ }
+ }
+ /*
+ * Now we are fixing a bug of gnu tar ...
+ * The first number should be zero, othewise we
+ * correct all the numbers.
+ * If tar_first_recno is .lt. zero, no recno is read
+ * up to now.
+ */
+ if (tar_first_recno < 0)
+ tar_first_recno = recno;
+ recno -= tar_first_recno;
+ /*
+ * Calculate the block number of the record.
+ */
+#ifdef DDS_TRACE
+ fprintf(stderr,"file-loc(%d,%d)\n",recno,tar_fb);
+#endif
+ blkno = recno / tar_bs;
+ recno -= blkno * tar_bs;
+ if ( vid != HP ) blkno *= tar_bs ;
+#ifdef DDS_TRACE
+ fprintf(stderr,"file-loc(%d:%d,%d)\n",tar_bs,blkno,recno);
+#endif
+ blkno += tar_fb;
+#ifdef DDS_TRACE
+ fprintf(stderr,"file-loc(%d:%d,%d)\n",tar_bs,blkno,recno);
+#endif
+ if (name == NULL) { /* calculate only once */
+ if ( strlen(cur_line) >= (66) ) {
+ name = cur_line + (65);
+ while ( ( name[ 0] != '\0' )
+ && (( ( name[-1] != ' ' )
+ || ( name[-6] != ' ' )
+ || ( name[-9] != ':' )
+ )&&( ( name[-1] != ' ' )
+ || ( name[-4] != ':' )
+ || ( name[-7] != ' ' )
+ || ( name[-10] != '-' )
+ || ( name[-13] != '-' )
+ ))
+ ) name++ ;
+ if ( name[0] == '\0' ) {
+ name = cur_line + (16+so);
+ }
+ } else {
+ if ( strlen(cur_line) <= (16+so) ) {
+ strcat(cur_line,
+ " ");
+ }
+ name = cur_line + (16+so);
+ }
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+ fprintf(stderr,"filename=%s\n",name);
+#endif
+ }
+ while ( ( name[ 0] != '\0' )
+ && ( name != ( cur_line + (16+so) ) )
+ && (( ( name[-1] != ' ' )
+ || ( name[-6] != ' ' )
+ || ( name[-9] != ':' )
+ )&&( ( name[-1] != ' ' )
+ || ( name[-4] != ':' )
+ || ( name[-7] != ' ' )
+ || ( name[-10] != '-' )
+ || ( name[-13] != '-' )
+ ))
+ ) name++ ;
+ }
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+#endif
+ i = strlen(name) -1 ;
+ if (name[i] == '\n') name[i] = '\0', i-- ;
+ /*
+ * We leave the list of directories empty on quick mode.
+ */
+ if (( name[i] == '/' )&&( quick_mode == 0 )) {
+ struct dir_list *dp;
+ for (i = 0 , dp = dl ; i < de; i++ , dp ++ ) {
+ if (strstr(name, dp->n) != name)
+ break;
+ }
+ strcpy(dp->n, name);
+ dp->b = blkno;
+ dp->r = recno;
+ de = i + 1 ;
+ }
+ /*
+ * Now we try to match one pattern with the name.
+ */
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+ fprintf(stderr,"scanning pattern list for '%s'\n",name);
+#endif
+ p = pattern_list;
+ while (*p != NULL) {
+ static int ll_blkno = -1 ;
+ static int ll_recno = -1 ;
+ static int ln_blkno = -1 ;
+ static int ln_recno = -1 ;
+ static const char *ll = "././@LongLink" ;
+#ifdef DDS_TRACE
+ fprintf(stderr," p = '%p' , *p = %p \n",p,*p);
+#endif
+ /*
+ * Thanks Andreas Bagge for this trick.
+ * I use the fnmatch function from the
+ * source of gnu tar.
+ */
+#ifdef DDS_TRACE
+ fprintf(stderr,"fnmatch '%s' for '%s'\n",name,*p);
+#endif
+ if (0 == fnmatch(*p, name, FNM_LEADING_DIR)) {
+ struct dir_list *dp;
+ for (i = 0, dp = dl; i < de; i++, dp++) {
+ char *p = strstr(name, dp->n);
+ if (p == name) {
+ extract(dp->n, dp->b, dp->r);
+ } else break ;
+ }
+ de = 0;
+ if ( ln_blkno >= 0 ) extract(
+ "././@LongLink",
+ ln_blkno,
+ ln_recno);
+ if ( ll_blkno >= 0 ) extract(
+ "././@LongLink",
+ ll_blkno,
+ ll_recno);
+ extract(name, blkno, recno);
+ break;
+ }
+ if ( 0==strncmp(ll,name,strlen(name)) ){
+ if ( ln_blkno < 0 )
+ ln_blkno = blkno , ln_recno = recno ;
+ else
+ ll_blkno = blkno , ll_recno = recno ;
+ } else {
+ ln_blkno = -1 ;
+ ln_recno = -1 ;
+ ll_blkno = -1 ;
+ ll_recno = -1 ;
+ }
+ p++;
+ }
+#ifdef DDS_TRACE
+ fprintf(stderr,"end of scanning pattern list\n");
+#endif
+ }
+ /*
+ * Write an empty record to the end of the archive.
+ */
+ memset(cur_block, 0, buf_n );
+ write(1, cur_block, 512);
+ nblocks++;
+ if (verbose)
+ fprintf(stderr, "dds2tar: %d blocks written\n", nblocks);
+#ifdef DDS_TRACE
+ fprintf(stderr,"%d\n",__LINE__);
+ fprintf(stderr,"return of dds_cmp(...)");
+#endif
+ return 0;
+}
--- /dev/null
+
+/*
+ * This file is part of dds2tar.
+ * Copyright by J"org Weule
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mtio.h>
+#include <unistd.h>
+#include <string.h>
+#include "dds2tar.h"
+#include "dds_tape.h"
+
+static int cur_rec;
+static int cur_byte;
+static const char hash_sign = '#';
+
+/********
+ * Skip to the next block.
+ *
+ ********************************************************************/
+void dds_index_skip(){
+ /*
+ * The hp-DAT is slowed down with dds_getpos().
+ * Is there a reason for this?
+ *
+ * Now the cur_blkno is incremented.
+ */
+ cur_rec -= cur_bs;
+ dds_read_next_block();
+ cur_byte += cur_n;
+ if (hash_mode == 1)
+ if ((cur_blkno & 0x1f) == 0) {
+ if ((cur_blkno & 0x7ff) == 0) {
+ fprintf(stderr, " %d\n",cur_byte);
+ fflush(stderr);
+ }
+ write(2, &hash_sign, 1);
+ }
+}
+
+/********
+ * Converting a tar-record to an entry in the index file.
+ *
+ * input: tar_record is the header of one file in the archive.
+ * The location of the header is given by the
+ * block and index value.
+ * output: The returned index is the location of the next header.
+ * Normalization of the pair (block,rec) with respect to
+ * the block length will give the right position.
+ * extern: index_fp, verbose
+ * index_fp is the FILE to write the rec.
+ * verbose indicates the loggin mode.
+ *
+ * If the name length of the file name is zero,
+ * and an empty block is found, the end
+ * of the archive is found and the program stops.
+ *
+ ********************************************************************/
+static int
+dds_index_h(tar_record *const ptr, int const block, int rec)
+{
+ int size;
+ char *p = ptr->hdr.magic;
+
+#ifdef DDS_TRACE
+ fputs("dds_index_h()\n", stderr);
+#endif
+
+ if ( dds_is_tar_header_record(ptr) == 0 ) {
+ fprintf(stderr,"dds2index: skipping to next header\n");
+ return ( rec + 1 ) ;
+ }
+
+ if (*p == 0)
+ p = "magic ";
+ if (ptr->hdr.linkflag == 'V') p = "label ";
+ else if (p[6] == ' ')
+ p[6] = 0;
+ if (ptr->hdr.name[0] == 0) {
+ int i = 0;
+
+ while ((((char *) ptr)[i] == 0) && (i < 512))
+ i++;
+ if (i == 512) {
+ fprintf(index_fp, dds_index_format,
+ "-end- ",
+ block,
+ rec,
+ 0, "(null)");
+ close(device);
+ exit(0);
+ }
+ }
+ if (ptr->hdr.size[0] != 0)
+ sscanf(ptr->hdr.size, "%o", &size);
+ else
+ size = 0;
+ long_name_len = 0 ;
+ if ( ptr->hdr.linkflag == LF_LONGNAME ) long_name_len = size ;
+
+ {
+ char *name = ptr->hdr.name ;
+ if ( ptr->hdr.linkflag != LF_LONGLINK &&
+ ptr->hdr.linkflag != LF_LONGNAME &&
+ long_name[0] != '\0' ) name = long_name ;
+ sprintf(cur_line, dds_index_format,
+ p,
+ block,
+ rec,
+ size,
+ name
+ );
+ fputs(cur_line, index_fp);
+ if ( ptr->hdr.linkflag != LF_LONGLINK &&
+ ptr->hdr.linkflag != LF_LONGNAME ) {
+ long_name[0] = '\0' ;
+ }
+ }
+ if (verbose)
+ fputs(cur_line, stderr);
+ /* calculate the number of records */
+ /* there was one header record */
+ size += 511 + 512;
+ size >>= 9;
+ rec += size;
+ return rec;
+}
+
+/********
+ * Converting a table line to the numbers.
+ *
+ */
+int
+rt_line(
+ int *const ptr_blkno,
+ int *const ptr_recno,
+ int *const ptr_size,
+ char **const ptr_name
+)
+{
+ char p[16];
+ int i;
+ char const *dds_fmt = NULL;
+
+#ifdef DDS_TRACE
+ fprintf(stderr,"rt_line(...)\n");
+#endif
+
+ if (cur_line[16] == ':') {
+ dds_fmt = dds_old_index_scan_format ;
+ *ptr_name = cur_line + 27;
+ } else {
+ if (cur_line[17] == ':') {
+ dds_fmt = dds_index_scan_format ;
+ *ptr_name = cur_line + 28;
+ } else return 1 ;
+ } ;
+
+ if ((i = sscanf(cur_line,
+ dds_fmt,
+ p,
+ ptr_blkno,
+ ptr_recno,
+ ptr_size)) < 4)
+ fprintf(stderr, "Wrong line inside the index file,"
+ " scanned %d values\n", i);
+#ifdef DDS_TRACE
+ fprintf(stderr,"end >> rt_line(...)\n");
+#endif
+ return 0 ;
+}
+
+/* procedure to create the index table */
+/********
+ * input: none
+ * output: none
+ * extern: device, index_fp
+ *
+ * The archive is read, and the index file is written.
+ *
+ ************************************************************/
+
+int
+dds_index(void)
+{
+
+
+#ifdef DDS_TRACE
+ fputs("dds_index()\n", stderr);
+#endif
+
+
+ fputs(dds_headline, index_fp);
+ if (verbose) fputs(dds_headline, index_fp);
+ next_blkno = -1 ;
+ cur_rec = 0;
+ dds_read_block();
+ cur_byte = cur_n;
+ if (hash_mode == 1)
+ if ((cur_blkno & 0x1f) == 0) {
+ write(2, &hash_sign, 1);
+ }
+ while (cur_n > 0) {
+ cur_bs = cur_n >> 9;
+ while (cur_rec < cur_bs) {
+ int new_rec ;
+ new_rec = dds_index_h(
+ cur_block + cur_rec,
+ cur_blkno,
+ cur_rec
+ );
+ if ( long_name_len > 0 ) {
+ int i = 0 ;
+ while ( long_name_len > (i<<9) ){
+ cur_rec++;
+ /*
+ * note: dds_index_skip operates on
+ * cur_rec
+ */
+ if ( cur_rec >= cur_bs )
+ dds_index_skip();
+ memcpy(long_name+((i++)<<9),
+ cur_block+cur_rec,
+ 512);
+ }
+ long_name_len = 0 ;
+ /* Now go to the next block behind the
+ long name */
+ cur_rec++;
+ }
+ else cur_rec = new_rec ;
+ }
+ dds_index_skip();
+ }
+ if (cur_n <= 0) {
+ perror("dds2tar");
+ fprintf(stderr, "dds_index: unexpected end of tar archive \n");
+ close(device);
+ exit(9);
+ }
+ return 0;
+}
+
--- /dev/null
+#include <stdio.h>
+#include "dds2tar.h"
+int dds_unquote(char*p){
+ char *q ;
+
+ /* do nothing if there is no quote */
+ while ( *p && *p != '\\' ) p++ ;
+ if ( *p == '\0' ) return 1 ;
+
+ q = p ;
+ while ( *p ){
+ if ( *p == '\\' ) {
+ char c = p[1] ;
+ switch (c){
+ case '\\' : *q++ = '\\' , p+=2 ; continue ;
+ case 't' : *q++ = '\t' , p+=2 ; continue ;
+ case 'n' : *q++ = '\n' , p+=2 ; continue ;
+ case 'f' : *q++ = '\f' , p+=2 ; continue ;
+ case 'b' : *q++ = '\b' , p+=2 ; continue ;
+ case 'r' : *q++ = '\r' , p+=2 ; continue ;
+ case '?' : *q++ = '\177' , p+=2 ; continue ;
+ }
+ if ( '0' <= c && c <= '9' ){
+ int x = 0 ;
+ int n = 0 ;
+ sscanf(p+1,"%03o%n",&x,&n);
+ *q++ = x ; p+=n+1 ; continue ;
+ }
+ /*
+ * Here we should never be, but if, we just proceed.
+ */
+ }
+ *q++ = *p++ ;
+ }
+ *q++ = '\0' ;
+ return 1 ;
+}
+
+#ifdef TEST_IT
+int main(int argc,char*argv[]){
+ if ( argc < 2 ) return 0 ;
+ dds_unquote(argv[1]);
+ puts(argv[1]);
+ return 0 ;
+}
+#endif
+
--- /dev/null
+
+/*
+ * This file is part of dds2tar.
+ * Copyright by J"org Weule
+ *
+ * Special thanks to Les.Grant@mitsuibabcock.co.uk
+ * for the HP-UX patch.
+ */
+
+#include <stdlib.h>
+#include <stdio.h> /* fpirntf() */
+#include <errno.h> /* perror() */
+#include <sys/mtio.h> /* MTSEEK ... */
+#include <sys/ioctl.h> /* ioctl() */
+#include <unistd.h> /* close() exit() */
+#include "dds_tape.h"
+
+#include "dds2tar.h"
+#include "dds_tape.h"
+
+/*
+ * set scsi2logical
+ */
+int dds_scsi2logical(void){
+ struct mtop p ;
+ p.mt_op = MTSETDRVBUFFER ;
+ p.mt_count = MT_ST_OPTIONS|MT_ST_SCSI2LOGICAL ;
+ fputs("scsi2logical\n",stderr);
+ return ioctl(device,MTIOCTOP,&p);
+}
+
+/*
+ * set read_ahead
+ */
+int dds_read_ahead(void){
+ struct mtop p ;
+ int r ;
+ p.mt_op = MTSETDRVBUFFER ;
+ p.mt_count = MT_ST_OPTIONS|MT_ST_READ_AHEAD ;
+ r = ioctl(device,MTIOCTOP,&p);
+#ifdef DDS_TRACE
+ fputs("read_ahead\n",stderr);
+ if ( r < 0 ) perror("Read_ahead");
+#endif
+ return r ;
+}
+
+/*
+ * rewind the last block
+ */
+int dds_bsr(void){
+ struct mtop p ;
+ p.mt_op = MTBSR ;
+ p.mt_count = 1 ;
+ return ioctl(device,MTIOCTOP,&p);
+}
+
+#ifdef MTGETBLK
+/*
+ * get block size
+ */
+int dds_get_bs(void){
+ struct mtop p ;
+ int r ;
+ p.mt_op = MTGETBLK ;
+ p.mt_count = 0 ;
+ r = ioctl(device,MTSETBLK,&p);
+ if ( r >= 0 ) r = p.mt_count ;
+ return r ;
+}
+#endif
+
+/*
+ * set block size
+ */
+int dds_set_bs(int n){
+ struct mtop p ;
+ p.mt_op = MTSETBLK ;
+ p.mt_count = n ;
+ tar_bs = n >> 9 ;
+ tar_n = n ;
+#ifdef DDS_TRACE
+ fprintf(stderr,"record_size=%d\n",n);
+#endif
+ return ioctl(device,MTSETBLK,&p);
+}
+
+/*
+ * To read one line of the device and check for errors, we use the following
+ * code. If a filemark is read, we try the block again.
+ *
+ * Note that cur_blkno and next_blkno is changed.
+ */
+void
+dds_read_next_block(void)
+{
+ int err = 0;
+
+#ifdef HPDAT
+ if (next_blkno == -1)
+#endif
+ next_blkno = dds_getpos(device);
+ cur_blkno = next_blkno;
+ cur_n = 0;
+#ifdef DDS_TRACE
+ fprintf(stderr, "begin --> read_next_block()\n");
+ fprintf(stderr, "vid=%d \n",vid);
+#endif
+ if ( vid == HP ) do {
+ /* If you write a tape with 'tar -b 256' on SunOS, reading */
+ /* the tape needs the following workaround. SunOS splits the */
+ /* block into three tape blocks of 65534, 65534 and 4 Bytes. */
+ /* dds2tar is reading the tree blocks and the number is */
+ /* the one of the first block. You can not use the tar */
+ /* listing block is this case, because the calculation of the */
+ /* right will fail. Note that 'dds2tar --dds-dd | tar ft -' */
+ /* will show the index of the archive, 'tar t' fails. */
+ /* */
+ /* --dds-dd is in experimental state, so may be I will change */
+ /* this. */
+#if ( ST_BUFFER_BLOCKS > 32 )
+ do {
+ err = read(device, ((char *) cur_block) + cur_n,
+ buf_n - cur_n);
+ if (err > 0) next_blkno++, cur_n += err;
+ } while ((err > 0) && (cur_n < buf_n) && ((cur_n & 0x1ff) != 0));
+#else
+ err = read(device, cur_block, buf_n);
+ if (err > 0) next_blkno++, cur_n += err ;
+#endif
+ if ((cur_n & 0x1ff) != 0) {
+ fprintf(stderr, "not a tar archive, record size is"
+ " %d bytes \n", cur_n);
+ exit(4);
+ }
+ /*
+ * We are done, if err >= 0.
+ */
+ if ( err >= 0 ) break ;
+
+ /*
+ * If err < 0 ... exit or decrease the buffer ...
+ */
+ if ((errno != EOVERFLOW) || (buf_n == 1)) {
+ perror("dds2tar");
+ exit(4);
+ }
+ buf_n >>= 1;
+ fprintf(stderr,"decreasing buffer to %d bytes\n",buf_n);
+ if (buf_n == 1) exit(4);
+ } while ( 1 );
+ if ( vid != HP ) {
+ err = read(device, cur_block, tar_n);
+ if ( err < 0 ) {
+ fprintf(stderr,
+ "Can not read from tape with blocksize of %d.\n",
+ tar_n);
+ perror("dds2index");
+ exit(4);
+ }
+ next_blkno += tar_bs , cur_n = err ;
+ if ((cur_n & 0x1ff) != 0) {
+ fprintf(stderr, "not a tar archive, record size is"
+ " %d bytes \n", cur_n);
+ exit(4);
+ }
+ }
+ cur_bs = cur_n >> 9;
+#ifdef DDS_TRACE
+ fprintf(stderr, "end ----> read_next_block()\n");
+#endif
+}
+
+void
+dds_read_block(void)
+{
+ do
+ dds_read_next_block();
+ while (cur_n == 0);
+}
+
+int
+dds_getpos(int const dev)
+{
+ int i,n;
+
+#ifdef MTIOCPOS
+ struct mtpos pos;
+ i = ioctl(dev, MTIOCPOS, &pos);
+ if (i != 0) {
+ perror("dds2tar: ioctl MTIOCPOS");
+#else
+ i = ioctl(dev, SIOC_GET_POSITION, &n); /* HP-UX */
+ if (i != 0) {
+ perror("dds2tar: ioctl SIOC_GET_POSITION");
+#endif
+ close(dev);
+ exit(11);
+ }
+ n = pos.mt_blkno;
+ if (n < 0) {
+ fprintf(stderr, "dds2tar: eom detected ? blkno = %d \n", n);
+ close(dev);
+ exit(12);
+ }
+ return n;
+}
+
+#ifdef MTIOCLOC
+int
+dds_getloc(int const dev)
+{
+ struct mtpos pos;
+ int i,n;
+
+ i = ioctl(dev, MTIOCPOS, &pos);
+ if (i != 0) {
+ perror("dds2tar: ioctl MTIOCLOC");
+ close(dev);
+ exit(11);
+ }
+ n = pos.mt_blkno;
+ if (n < 0) {
+ fprintf(stderr, "dds2tar: eom detected ? blkno = %d \n", n);
+ close(dev);
+ exit(12);
+ }
+ return n ;
+}
+#endif
+
+int
+dds_has_partitions(int const dev){
+#ifdef MT_ISDDS1
+ struct mtget p ;
+ int i;
+ i = ioctl(dev, MTIOCGET, &p );
+ if ( i >= 0 ) {
+ i = p.mt_type ;
+ } else perror("dds2tar");
+ /*
+ if(i==MT_ISDDS1)fprintf(stderr, "DDS2TAR: drive without partitions\n");
+ if(i==MT_ISDDS2)fprintf(stderr, "DDS2TAR: drive with partitions\n");
+ fprintf(stderr, "DDS2TAR: type = %x\n",i);
+ */
+ return i ;
+#else
+ return -1 ;
+#endif
+}
+
+int
+dds_seek(int const dev, int const blkno)
+{
+ struct mtop op;
+ int i;
+
+#ifdef SIOC_SET_POSITION
+ i = ioctl(dev, SIOC_SET_POSITION, &blkno);
+#else
+ op.mt_op = MTSEEK;
+ op.mt_count = blkno;
+ i = ioctl(dev, MTIOCTOP, &op);
+#endif
+ if (i != 0) {
+ perror("ioctl SEEK");
+ close(dev);
+ exit(13);
+ }
+ return 0;
+}
+
+/*
+ * This file is part of dds2tar.
+ * Copyright by J"org Weule
+ */
+
+#ifdef HPDAT
+#include <stdlib.h> /* malloc() */
+#include <stdio.h> /* printf() */
+#include <sys/ioctl.h> /* ioctl() */
+#include <string.h> /* memset() bcopy() */
+#include <unistd.h> /* exit() */
+#include "dds_tape.h"
+
+typedef unsigned char byte;
+
+typedef struct {
+ int inlen;
+ int outlen;
+ byte buf[1024];
+}
+
+ioctl_arg;
+
+static void
+copy_page(ioctl_arg * const arg, int const i)
+{
+
+ static struct {
+ char const *const text;
+ int const inlen;
+ int const outlen;
+ byte const buf[32];
+ }
+ const comp_page[7] =
+ {
+ {
+ "set_comp_off", 26, 128,
+ {
+ 0x15, 0x10, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x0f, 0x0e,
+ 0x40, 0x80, 0x00, 0x00,
+ 0x00, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ }
+ }
+ ,
+ {
+ "set_cpmp_on", 26, 128,
+ {
+ 0x15, 0x10, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x0f, 0x0e,
+ 0xc0, 0x80, 0x00, 0x00,
+ 0x00, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ }
+ }
+ ,
+ {
+ "get_comp", 6, 128,
+ {
+ 0x1a, 0x00, 0x0f, 0x00, 0x40, 0x00
+ }
+ }
+ ,
+ {
+ "log_comp", 10, 128,
+ {
+ 0x4d, 0x00, 0x79, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00
+ }
+ }
+ ,
+ {
+ "load_tape", 6, 128,
+ {
+ 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00
+ }
+ }
+ ,
+ {
+ "unload_tape", 6, 128,
+ {
+ 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00
+ }
+ }
+ ,
+ {
+ "mode_sense", 6, 128,
+ {
+ 0x1a, 0x00, 0x00, 0x00, 0x0C, 0x00
+ }
+ }
+ };
+
+ arg->inlen = comp_page[i].inlen;
+ arg->outlen = comp_page[i].outlen;
+ memset(arg->buf, 0, 1024);
+ bcopy(comp_page[i].buf, arg->buf, arg->inlen);
+}
+
+static int
+print_error(byte const *const b, int len)
+{
+
+ static char const *const sense_key[] =
+ {
+ "no sense", "recovered error", "not ready", "medium error",
+ "hardware error", "illegal request", "unit attention",
+ "data protect", "blank check", "vendor specific",
+ "copy aborted", "aborted command", "equal",
+ "volume overflow", "miscompare", "reserved"
+ };
+
+ int i;
+
+ if (len > 32)
+ len = 8 + b[7];
+ printf(" err: ");
+ for (i = 0; i < len; i++)
+ printf(" %2X", b[i]);
+ printf("\n");
+ printf("error sense: %s\n", sense_key[b[2] & 0xf]);
+ printf("asc + ascq = %2x %2x\n", b[12], b[13]);
+ return 0;
+}
+
+void
+set_compression_mode(int dev, int const comp_mode)
+{
+ ioctl_arg *arg;
+
+ if (comp_mode < 0 || comp_mode > 5)
+ return;
+ /*
+ * Allocate memory.
+ */
+ arg = malloc(sizeof (ioctl_arg));
+ if (arg == NULL) {
+ fprintf(stderr, "dds2tar: not enough memory\n");
+ exit(15);
+ }
+ /*
+ * do ioctl
+ */
+ copy_page(arg, comp_mode);
+ /* arg->buf[12] = (comp_mode << 7) | 0x40; */
+ if (ioctl(dev, 1, arg) != 0) {
+ close(dev);
+ print_error(arg->buf, arg->inlen);
+ exit(16);
+ }
+ if (comp_mode == DDSCM_QUERY) {
+ byte *b;
+
+ b = arg->buf + 12;
+ fprintf(stderr, "data compression enable %d\n", b[2] >> 7);
+ } else if (comp_mode == DDSCM_LOG) {
+ int i, j;
+ byte *b;
+
+ b = arg->buf + 0;
+ for (i = 0; i < b[3];) {
+
+ static char const *const tab39[] =
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "kilobytes to data compression",
+ "kilobytes from data compression",
+ "kilobytes to tape",
+ "kilobytes from tape",
+ NULL,
+ NULL,
+ NULL};
+
+ byte *p = b + i + 4;
+ int n, k, c;
+
+ c = (p[0] << 8) + p[1];
+ n = p[3];
+ i += 4 + n;
+ p += 4;
+ j = 0;
+ for (k = 0; k < n; k++)
+ j = (j << 8) + p[k];
+
+ if ((c < 12) && (tab39[c] != NULL))
+ printf("%s: %d\n", tab39[c], j);
+ }
+ }
+}
+
+#endif
--- /dev/null
+
+/*
+ * This file is part of dds2tar.
+ * Copyright by J"org Weule
+ */
+
+extern int dds_scsi2logical(void);
+extern int dds_bsr(void);
+extern void dds_read_block(void);
+extern void dds_read_next_block(void);
+extern int dds_getpos(int const dev);
+extern int dds_seek(int const dev ,int const blkno);
+extern int dds_get_bs(void);
+extern int dds_read_ahead(void);
+
+extern int dds_has_partitions(int const dev);
+
+#define DDSCM_NULL -1
+#define DDSCM_OFF 0
+#define DDSCM_ON 1
+#define DDSCM_QUERY 2
+#define DDSCM_LOG 3
+#define DDSCM_LOAD 4
+#define DDSCM_UNLOAD 5
+#define DDSCM_FILENO 6
+#define DDSCM_LOGICAL 7
+#define DDSCM_WHERE 8
+
+extern void set_compression_mode(int _device, const int _mode);
+
--- /dev/null
+#!/bin/sh
+# This tool is in experimental status.
+#
+# Send me an email, if you have nice ideas.
+# weule@uni-duesseldorf.de
+#
+#====================================================================
+# Usage:
+#
+# First label a tape:
+# ddstool create-label 'unique-string and more strings'
+#
+# To archive something:
+# ddstool append pathnames...
+#
+# To delete the old index-files and make a new label:
+# ddstool new-label 'unique-string and more strings'
+#
+# Each index is stored by the pathnames:
+# $A/$unique-string.$file-number (soft link)
+# $A/$timestamp-of-the-tapelabel.$file-number (file)
+#
+#====================================================================
+# Sorry that I don't know the right method to extract something.
+# For now it's more save to do it by hand.
+#
+#====================================================================
+#
+set -v
+A=/data/tape
+case "$1" in
+append)
+ mt rewind;
+ L=`mt-dds label | awk '{print $1}' `
+ T=`mt-dds ts`
+ mt rewind
+ mt eom
+ mt status | grep file
+ F=`mt status | awk '{ if ($1 == "file") printf("%02d",$4) }'`
+ echo $A/$T.$F $A/$L.$F
+ touch $A/$T.$F
+ ln -f -s $A/$T.$F $A/$L.$F
+ shift
+ tar --label "$L" -b 32 -R -v -v --record-file $A/$T.$F --create $*
+;;
+create-label)
+ mt rewind
+ tar --create --label "$2" -b 2
+;;
+new-label)
+ mt rewind;
+ L=`mt-dds label | awk '{print $1}' `
+ T=`mt-dds ts`
+ mt rewind
+ rm $A/$L.* $A/$T.*
+ L=`echo "$2" | awk '{print $1}'`
+ if test -f $L.01 ; then
+ echo $0: ERROR: Label ist schon bekannt!
+ else
+ tar --create --label "$2" -b 2
+ mt rewind
+ T=`mt-dds ts`
+ F=00
+ tar -b 1 -t -v -v -R --record-file $A/$T.$F
+ ln -f -s $A/$T.$F $A/$L.$F
+ fi
+;;
+index)
+ mt rewind;
+ L=`mt-dds label | awk '{print $1}' `
+ T=`mt-dds ts`
+ mt rewind
+ B=`mt-dds blksize`
+ echo $B
+ tar -v -v -R -t -b $B --record-file $A/$T.$F
+ mt rewind
+ mt asf "$2"
+ F=`mt status | awk '{ if ($1 == "file") printf("%02d",$4) }'`
+ echo File = $F
+ echo $A/$T.$F $A/$L.$F
+ touch $A/$T.$F
+ ln -f -s $A/$T.$F $A/$L.$F
+ B=`mt-dds blksize`
+ echo Blksize = $B
+ tar -b $B -t -R -v -v --record-file $A/$T.$F
+esac
+mt rewind
--- /dev/null
+magic record blk: size name
+ustar 0 0: 0 ./
+ustar 0 1: 6375 Makefile
+ustar 0 15: 12946 Changes
+ustar 2 2: 7979 README
+ustar 2 19: 11045 dds2tar.man
+ustar 4 2: 2837 dds2index.man
+ustar 4 9: 3919 mt-dds.man
+ustar 4 18: 1666 dds-dd.man
+ustar 5 3: 25773 dds2tar.ps
+ustar 7 15: 10333 dds2index.ps
+ustar 8 17: 11993 mt-dds.ps
+ustar 10 2: 7935 dds-dd.ps
+ustar 10 19: 2388 dds2tar.h
+ustar 11 5: 22264 dds2tar.c
+ustar 13 10: 13073 dds_extract.c
+ustar 14 17: 1141 zf-cre-open.h
+ustar 15 1: 4336 zf-cre-open.c
+ustar 15 11: 5229 dds_index.c
+ustar 16 3: 687 dds_tape.h
+ustar 16 6: 9113 dds_tape.c
+ustar 17 5: 691 dds_chkhdr.c
+ustar 17 8: 1321 scsi_vendor
+ustar 17 12: 10043 tar-1.11.2.patch
+ustar 18 13: 14757 tar-1.11.8.patch
+ustar 20 3: 14579 tar-1.12.patch
+ustar 21 13: 294 tar-1.11.2-sparse-files.patch
+ustar 21 15: 353 tar-1.11.2-sparse-files.README
+ustar 21 17: 4961 dds2tar-test.sh
+ustar 22 8: 0 dds2index
+ustar 22 9: 0 mt-dds
+ustar 22 10: 0 dds2tar-test-tape-link-soft
+ustar 22 11: 100 .indent.pro
+ustar 22 13: 1276 dds2tar.lsm
+ustar 22 17: 17982 COPYING
+ustar 24 14: 2104 ddstool
+ustar 25 0: 422 e.c
+ustar 25 2: 10240 x.tar
+ustar 26 3: 0 tdir/
+ustar 26 4: 0 tdir/ä.txt
+ustar 26 5: 11890 e
+ustar 27 10: 12579 dds_quote
+ustar 28 16: 1010 dds_quote.c
+ustar 28 19: 62720 dds2tar.o
+ustar 35 3: 22492 dds_index.o
+ustar 37 8: 28448 dds_extract.o
+ustar 40 5: 25844 dds_tape.o
+ustar 42 17: 11344 dds_quote.o
+ustar 44 1: 24180 zf-cre-open.o
+ustar 46 10: 17288 dds_chkhdr.o
+ustar 48 5: 119244 dds2tar
+ustar 59 19: 0 dds2tar-test-tape-link-hard
+ustar 60 0: 0 dds-dd
+ustar 60 1: 11045 dds2tar.1
+ustar 61 4: 2837 dds2index.1
+ustar 61 11: 3919 mt-dds.1
+ustar 62 0: 1666 dds-dd.1
+ustar 62 5: 15888 tar-1.13.patch
+ustar 63 18: 131 ././@LongLink
+ustar 64 0: 0 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+ustar 64 1: 131 ././@LongLink
+ustar 64 3: 141 ././@LongLink
+ustar 64 5: 0 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+-end- 64 6: 0 (null)
--- /dev/null
+loc number of the file is 1
+loc number of the first block is 65
+loc block length is 16384 bytes = 32 * 512 bytes
+rec 0: block 0: dds2tar
+rec 1: block 1: ./
+rec 2: block 2: Makefile
+rec 16: block 16: Changes
+rec 11: block 43: README
+rec 28: block 60: dds2tar.man
+rec 19: block 83: dds2index.man
+rec 26: block 90: mt-dds.man
+rec 3: block 99: dds-dd.man
+rec 8: block 104: dds2tar.ps
+rec 28: block 156: dds2index.ps
+rec 18: block 178: mt-dds.ps
+rec 11: block 203: dds-dd.ps
+rec 28: block 220: dds2tar.h
+rec 2: block 226: dds2tar.c
+rec 15: block 271: dds_extract.c
+rec 10: block 298: zf-cre-open.h
+rec 14: block 302: zf-cre-open.c
+rec 24: block 312: dds_index.c
+rec 4: block 324: dds_tape.h
+rec 7: block 327: dds_tape.c
+rec 26: block 346: dds_chkhdr.c
+rec 29: block 349: scsi_vendor
+rec 1: block 353: tar-1.11.2.patch
+rec 22: block 374: tar-1.11.8.patch
+rec 20: block 404: tar-1.12.patch
+rec 18: block 434: tar-1.11.2-sparse-files.patch
+rec 20: block 436: tar-1.11.2-sparse-files.README
+rec 22: block 438: dds2tar-test.sh
+rec 1: block 449: dds2index
+rec 2: block 450: mt-dds
+rec 3: block 451: dds2tar-test-tape-link-soft
+rec 4: block 452: .indent.pro
+rec 6: block 454: dds2tar.lsm
+rec 10: block 458: COPYING
+rec 15: block 495: ddstool
+rec 21: block 501: e.c
+rec 23: block 503: x.tar
+rec 12: block 524: tdir/
+rec 13: block 525: tdir/\344.txt
+rec 14: block 526: e
+rec 7: block 551: dds_quote
+rec 1: block 577: dds_quote.c
+rec 4: block 580: dds2tar.o
+rec 0: block 704: dds_index.o
+rec 13: block 749: dds_extract.o
+rec 6: block 806: dds_tape.o
+rec 26: block 858: dds_quote.o
+rec 18: block 882: zf-cre-open.o
+rec 3: block 931: dds_chkhdr.o
+rec 6: block 966: dds2tar
+rec 16: block 1200: dds2tar-test-tape-link-hard
+rec 17: block 1201: dds-dd
+rec 18: block 1202: dds2tar.1
+rec 9: block 1225: dds2index.1
+rec 16: block 1232: mt-dds.1
+rec 25: block 1241: dds-dd.1
+rec 30: block 1246: tar-1.13.patch
+rec 31: block 1279: ././@LongLink
+rec 1: block 1281: 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+rec 2: block 1282: ././@LongLink
+rec 4: block 1284: ././@LongLink
+rec 6: block 1286: 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
--- /dev/null
+first block number is 0
+block size is 20
+block length is 10240
+loc number of the file is 0
+loc number of the first block is 0
+rec 0: block 0: ./
+rec 1: block 1: Makefile
+rec 15: block 15: Changes
+rec 2: block 42: README
+rec 19: block 59: dds2tar.man
+rec 2: block 82: dds2index.man
+rec 9: block 89: mt-dds.man
+rec 18: block 98: dds-dd.man
+rec 3: block 103: dds2tar.ps
+rec 15: block 155: dds2index.ps
+rec 17: block 177: mt-dds.ps
+rec 2: block 202: dds-dd.ps
+rec 19: block 219: dds2tar.h
+rec 5: block 225: dds2tar.c
+rec 10: block 270: dds_extract.c
+rec 17: block 297: zf-cre-open.h
+rec 1: block 301: zf-cre-open.c
+rec 11: block 311: dds_index.c
+rec 3: block 323: dds_tape.h
+rec 6: block 326: dds_tape.c
+rec 5: block 345: dds_chkhdr.c
+rec 8: block 348: scsi_vendor
+rec 12: block 352: tar-1.11.2.patch
+rec 13: block 373: tar-1.11.8.patch
+rec 3: block 403: tar-1.12.patch
+rec 13: block 433: tar-1.11.2-sparse-files.patch
+rec 15: block 435: tar-1.11.2-sparse-files.README
+rec 17: block 437: dds2tar-test.sh
+rec 8: block 448: dds2index
+rec 9: block 449: mt-dds
+rec 10: block 450: dds2tar-test-tape-link-soft
+rec 11: block 451: .indent.pro
+rec 13: block 453: dds2tar.lsm
+rec 17: block 457: COPYING
+rec 14: block 494: ddstool
+rec 0: block 500: e.c
+rec 2: block 502: x.tar
+rec 3: block 523: tdir/
+rec 4: block 524: tdir/\344.txt
+rec 5: block 525: e
+rec 10: block 550: dds_quote
+rec 16: block 576: dds_quote.c
+rec 19: block 579: dds2tar.o
+rec 3: block 703: dds_index.o
+rec 8: block 748: dds_extract.o
+rec 5: block 805: dds_tape.o
+rec 17: block 857: dds_quote.o
+rec 1: block 881: zf-cre-open.o
+rec 10: block 930: dds_chkhdr.o
+rec 5: block 965: dds2tar
+rec 19: block 1199: dds2tar-test-tape-link-hard
+rec 0: block 1200: dds-dd
+rec 1: block 1201: dds2tar.1
+rec 4: block 1224: dds2index.1
+rec 11: block 1231: mt-dds.1
+rec 0: block 1240: dds-dd.1
+rec 5: block 1245: tar-1.13.patch
+rec 18: block 1278: ././@LongLink
+rec 0: block 1280: 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+rec 1: block 1281: ././@LongLink
+rec 3: block 1283: ././@LongLink
+rec 5: block 1285: 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+block 1286: ** Block of NULs **
--- /dev/null
+loc number of the file is 2
+loc number of the first block is 106
+loc block length is 16384 bytes = 32 * 512 bytes
+rec 0: block 0: drwxr-x--- weule/users 0 2000-08-17 00:16 ./
+rec 1: block 1: -rw-r----- weule/users 6375 2000-08-17 00:15 Makefile
+rec 15: block 15: -rw-r----- weule/users 12946 2000-08-13 15:15 Changes
+rec 10: block 42: -rw-r----- weule/users 7979 1998-06-23 12:11 README
+rec 27: block 59: -rw-r----- weule/users 11045 1998-02-02 16:40 dds2tar.man
+rec 18: block 82: -rw-r----- weule/users 2837 1995-02-01 23:33 dds2index.man
+rec 25: block 89: -rw-r----- weule/users 3919 1995-02-01 23:34 mt-dds.man
+rec 2: block 98: -rw-r----- weule/users 1666 1996-03-10 17:05 dds-dd.man
+rec 7: block 103: -rw-r----- weule/users 25773 1998-02-02 16:42 dds2tar.ps
+rec 27: block 155: -rw-r----- weule/users 10333 1996-03-10 17:12 dds2index.ps
+rec 17: block 177: -rw-r----- weule/users 11993 1996-03-10 17:12 mt-dds.ps
+rec 10: block 202: -rw-r----- weule/users 7935 1996-03-10 17:12 dds-dd.ps
+rec 27: block 219: -rw-r----- weule/users 2388 2000-08-06 17:42 dds2tar.h
+rec 1: block 225: -rw-r----- weule/users 22264 2000-08-13 15:27 dds2tar.c
+rec 14: block 270: -rw-r----- weule/users 13073 2000-08-06 17:54 dds_extract.c
+rec 9: block 297: -rw-r----- weule/users 1141 2000-08-06 17:42 zf-cre-open.h
+rec 13: block 301: -rw-r----- weule/users 4336 2000-08-06 17:42 zf-cre-open.c
+rec 23: block 311: -rw-r----- weule/users 5229 2000-08-06 17:42 dds_index.c
+rec 3: block 323: -rw-r----- weule/users 687 2000-08-06 17:42 dds_tape.h
+rec 6: block 326: -rw-r----- weule/users 9113 2000-08-06 17:42 dds_tape.c
+rec 25: block 345: -rw-r----- weule/users 691 2000-08-06 17:42 dds_chkhdr.c
+rec 28: block 348: -rwxr-x--- weule/users 1321 1998-05-15 14:56 scsi_vendor
+rec 0: block 352: -rw-r----- weule/users 10043 1995-02-09 23:14 tar-1.11.2.patch
+rec 21: block 373: -rw-r----- weule/users 14757 1996-12-01 16:22 tar-1.11.8.patch
+rec 19: block 403: -rw-r----- weule/users 14579 2000-08-06 22:21 tar-1.12.patch
+rec 17: block 433: -rw-r----- weule/users 294 1995-02-02 21:56 tar-1.11.2-sparse-files.patch
+rec 19: block 435: -rw-r----- weule/users 353 1995-02-02 22:06 tar-1.11.2-sparse-files.README
+rec 21: block 437: -rwxr-x--- weule/users 4961 2000-08-13 15:45 dds2tar-test.sh
+rec 0: block 448: lrwxrwxrwx weule/users 0 2000-08-17 00:16 dds2index -> ./dds2tar
+rec 1: block 449: lrwxrwxrwx weule/users 0 2000-08-17 00:16 mt-dds -> ./dds2tar
+rec 2: block 450: lrwxrwxrwx weule/users 0 2000-08-17 00:16 dds2tar-test-tape-link-soft -> dds2tar
+rec 3: block 451: -rw-r----- weule/users 100 1994-10-09 23:21 .indent.pro
+rec 5: block 453: -rw-r----- weule/users 1276 2000-08-17 00:12 dds2tar.lsm
+rec 9: block 457: -rw-r----- weule/users 17982 1994-09-03 13:40 COPYING
+rec 14: block 494: -rwxr-x--- weule/users 2104 1995-02-05 23:51 ddstool
+rec 20: block 500: -rw-r----- weule/users 422 2000-08-06 17:42 e.c
+rec 22: block 502: -rw-r----- weule/users 10240 2000-08-06 14:32 x.tar
+rec 11: block 523: drwxr-x--- weule/users 0 2000-08-06 16:24 tdir/
+rec 12: block 524: -rw-r----- weule/users 0 2000-08-06 16:24 tdir/\344.txt
+rec 13: block 525: -rwxr-x--- weule/users 11890 2000-08-06 15:01 e
+rec 6: block 550: -rwxr-x--- weule/users 12579 2000-08-06 15:52 dds_quote
+rec 0: block 576: -rw-r----- weule/users 1010 2000-08-06 17:42 dds_quote.c
+rec 3: block 579: -rw-r----- weule/users 62720 2000-08-13 15:30 dds2tar.o
+rec 31: block 703: -rw-r----- weule/users 22492 2000-08-06 17:42 dds_index.o
+rec 12: block 748: -rw-r----- weule/users 28448 2000-08-06 17:54 dds_extract.o
+rec 5: block 805: -rw-r----- weule/users 25844 2000-08-06 17:42 dds_tape.o
+rec 25: block 857: -rw-r----- weule/users 11344 2000-08-06 17:42 dds_quote.o
+rec 17: block 881: -rw-r----- weule/users 24180 2000-08-06 17:42 zf-cre-open.o
+rec 2: block 930: -rw-r----- weule/users 17288 2000-08-06 17:42 dds_chkhdr.o
+rec 5: block 965: -rwxr-x--- weule/users 119244 2000-08-13 15:30 dds2tar
+rec 15: block 1199: -rwxr-x--- weule/users 0 2000-08-13 15:30 dds2tar-test-tape-link-hard link to dds2tar
+rec 16: block 1200: -rwxr-x--- weule/users 0 2000-08-13 15:30 dds-dd link to dds2tar
+rec 17: block 1201: -rw-r--r-- weule/users 11045 2000-08-06 15:56 dds2tar.1
+rec 8: block 1224: -rw-r--r-- weule/users 2837 2000-08-06 15:56 dds2index.1
+rec 15: block 1231: -rw-r--r-- weule/users 3919 2000-08-06 15:56 mt-dds.1
+rec 24: block 1240: -rw-r--r-- weule/users 1666 2000-08-06 15:56 dds-dd.1
+rec 29: block 1245: -rw-r----- weule/users 15888 2000-08-06 23:39 tar-1.13.patch
+rec 30: block 1278: Lrw-r----- root/root 0 2000-08-06 20:57 ././@LongLink unknown file type `L'
+rec 0: block 1280: -rw-r----- weule/users 0 2000-08-06 20:57 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+rec 1: block 1281: Krwxrwxrwx root/root 130 2000-08-06 20:57 ././@LongLink unknown file type `K'
+rec 3: block 1283: Lrwxrwxrwx root/root 0 2000-08-06 20:57 ././@LongLink unknown file type `L'
+rec 5: block 1285: lrwxrwxrwx weule/users 0 2000-08-06 20:57 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -> 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
--- /dev/null
+.TH mt-dds 1L 2.4 \" -*- nroff -*-
+.\"----------
+.SH NAME
+.\"----------
+mt-dds \- tool to control a dds device.
+.\"----------
+.SH SYNOPSIS
+.\"----------
+.B mt-dds
+.BR comp-on | comp-off | comp-query | comp-log
+.PD 0
+.PP
+.B mt-dds
+<
+.BR tell | label
+> [
+.B -b \ #
+]
+.PD 1
+.\"----------
+.SH DESCRIPTION
+.\"----------
+.B mt-dds
+controls the compression mode of dds tape devices (DAT).
+.PP
+.B mt-dds
+may also report the current tape position in
+absolute records (relative to begin of tape) in a format
+that may be used later by
+.B dds2tar(1)
+to access tar archives that are not the first file on tape.
+.PP
+The default device is
+.IR /dev/tape ,
+which may be overridden with the environment variable
+.BR TAPE ,
+which in turn may be overridden with the
+.BI -f \ device
+option. The device must be a character special file.
+.\"----------
+.SH OPTIONS
+.\"----------
+.SS DDS tape device control options
+
+.TP
+.B comp-on
+Enable the hardware compression mode if supported by the device.
+.TP
+.B comp-off
+Disable the compression mode, switch to normal mode.
+.TP
+.B comp-query
+Print to stderr if compression mode currently is disabled
+or enabled. A
+.B 0
+means compression is disabled, a
+.B 1
+means compression in enabled.
+.TP
+.B comp-log
+Print to stdout four lines of information about transferred kilobytes
+before and after hardware compression from and to the device
+since initialization.
+.\"----------
+.SS dds2tar service functions
+
+.TP
+.B tell
+Print three lines with the
+.BR "current tape position" ", a"
+.B block size
+value (20 by default, may be overridden with
+.B -b
+option) and a
+.B block length
+value (blocksize*512) to
+.IR stdout .
+If this output is redirected to a location file
+.IR locfile ,
+this file may be used by
+.B dds2tar(1)
+to access archives on tape.
+.TP
+.B label
+If the current tape position is the beginning of an archive and the archive
+is labeled,
+.B mt-dds
+writes the label to stdout
+and moves the tape back to the
+current position (or back over the filemark).
+.TP
+.B ts
+If the current tape position is the beginning of an archive and the archive
+is labeled,
+.B mt-dds
+writes the timestamp in octal format to stdout
+and moves the tape back to the
+current position (or back over the filemark).
+If you are using only one computer, the timestamp can be used as a unique
+archive identifier.
+.TP
+.BI -b \ #
+Specify the block size
+.I #
+value that is used as a default for the written value with the
+.B mt-dds tell
+command (see above).
+Also the internal buffer size is specified with this option
+which is used to read one block in order to get the block size
+of the current tape block. So specify the block size of the archive
+or a larger number.
+.\"----------
+.SS other options
+
+.TP
+.BI -f\ device
+Device of the tape archive (default is /dev/tape).
+Must be a character special file connected to a dds tape device.
+.TP
+.BR -V , --version
+Print the version number of
+.B mt-dds
+to stderr and exit immediately.
+.TP
+.B --help
+print some screens of online help with examples through a pager
+and exit immediately.
+.\"----------
+.SH EXAMPLES
+.\"----------
+.B Example 1:
+checking the compression mode of the default tape device
+.RS 10
+mt-dds comp-query
+.RE
+.PP
+.B Example 2:
+Write the location information as
+.B dds2tar
+command line options to stdout.
+.RS 10
+mt-dds
+.RE
+.PP
+.PD 1
+.\"----------
+.SH ENVIRONMENT
+.\"----------
+The environment variable
+.B TAPE
+overrides the default tape device /dev/tape.
+.TP
+PAGER
+The environment variable
+.B PAGER
+overrides the builtin pager command ("/bin/more") to display the output
+of the
+.B --help
+option.
+.\"----------
+.SH "SEE ALSO"
+.\"----------
+dds2tar(1), dds2index(1), mt(1), tar(1)
+.\"----------
+.SH HISTORY
+.\"----------
+This program was created to use it in conjunction with dds2tar.
+.\"----------
+.SH AUTHOR
+.\"----------
+J"org Weule (weule@cs.uni-duesseldorf.de), Phone +49 211 751409.
+This software is available at
+ftp.uni-duesseldorf.de:/pub/unix/apollo
+
--- /dev/null
+%!PS-Adobe-3.0
+%%Creator: groff version 1.09
+%%CreationDate: Sun Mar 10 17:12:17 1996
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.09 0
+%%Pages: 2
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.09 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72
+def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron
+/scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent
+/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen
+/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon
+/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
+/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex
+/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y
+/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft
+/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl
+/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen
+/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft
+/logicalnot/minus/registered/macron/degree/plusminus/twosuperior
+/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior
+/ordmasculine/guilsinglright/onequarter/onehalf/threequarters
+/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE
+/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
+/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn
+/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla
+/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
+/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash
+/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def
+/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0/Times-Bold RE
+/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 374.4(mt-dds\(1L\) mt-dds\(1L\))72 48 R/F1 9
+/Times-Bold@0 SF -.18(NA)72 84 S(ME).18 E F0
+(mt-dds \255 tool to control a dds de)108 96 Q(vice.)-.25 E F1(SYNOPSIS)
+72 112.8 Q/F2 10/Times-Bold@0 SF(mt-dds comp-on)108 124.8 Q F0(|)A F2
+(comp-off)A F0(|)A F2(comp-query)A F0(|)A F2(comp-log)A(mt-dds)108 136.8
+Q F0(<)2.5 E F2(tell)2.5 E F0(|)A F2(label)A F0 2.5(>[)2.5 G F2 2.5
+(-b #)B F0(])2.5 E F1(DESCRIPTION)72 160.8 Q F2(mt-dds)108 172.8 Q F0
+(controls the compression mode of dds tape de)2.5 E(vices \(D)-.25 E
+-1.11(AT)-.4 G(\).)1.11 E F2(mt-dds)108 196.8 Q F0 .547
+(may also report the current tape position in absolute records \(relati)
+3.048 F .847 -.15(ve t)-.25 H 3.047(ob).15 G -.15(eg)-3.047 G .547
+(in of tape\) in a format).15 F(that may be used later by)108 208.8 Q F2
+(dds2tar\(1\))2.5 E F0(to access tar archi)2.5 E -.15(ve)-.25 G 2.5(st)
+.15 G(hat are not the \214rst \214le on tape.)-2.5 E .726(The def)108
+232.8 R .726(ault de)-.1 F .726(vice is)-.25 F/F3 10/Times-Italic@0 SF
+(/de)3.226 E(v/rmt0)-.15 E F0 3.226(,w).47 G .726(hich may be o)-3.226 F
+-.15(ve)-.15 G .726(rridden with the en).15 F .726(vironment v)-.4 F
+(ariable)-.25 E F2 -.9(TA)3.226 G(PE).9 E F0 3.226(,w)C .726(hich in)
+-3.226 F(turn may be o)108 244.8 Q -.15(ve)-.15 G(rridden with the).15 E
+F2(-f)2.5 E F3(de)2.5 E(vice)-.15 E F0(option. The de)2.5 E
+(vice must be a character special \214le.)-.25 E F1(OPTIONS)72 268.8 Q
+F2(DDS tape de)87 280.8 Q(vice contr)-.15 E(ol options)-.18 E(comp-on)
+108 292.8 Q F0(Enable the hardw)144 304.8 Q
+(are compression mode if supported by the de)-.1 E(vice.)-.25 E F2
+(comp-off)108 328.8 Q F0
+(Disable the compression mode, switch to normal mode.)144 340.8 Q F2
+(comp-query)108 364.8 Q F0 .94
+(Print to stderr if compression mode currently is disabled or enabled.)
+144 376.8 R(A)5.94 E F2(0)3.44 E F0 .94(means compression is)3.44 F
+(disabled, a)144 388.8 Q F2(1)2.5 E F0(means compression in enabled.)2.5
+E F2(comp-log)108 412.8 Q F0 .005(Print to stdout four lines of informa\
+tion about transferred kilobytes before and after hardw)144 424.8 R .005
+(are com-)-.1 F(pression from and to the de)144 436.8 Q
+(vice since initialization.)-.25 E F2(dds2tar ser)87 460.8 Q
+(vice functions)-.1 E(tell)108 472.8 Q F0 .095
+(Print three lines with the)22.67 F F2(curr)2.594 E .094
+(ent tape position)-.18 F F0 2.594(,a)C F2 .094(block size)B F0 -.25(va)
+2.594 G .094(lue \(20 by def).25 F .094(ault, may be o)-.1 F -.15(ve)
+-.15 G(rrid-).15 E .002(den with)144 484.8 R F2(-b)2.502 E F0 .002
+(option\) and a)2.502 F F2 .002(block length)2.502 F F0 -.25(va)2.502 G
+.003(lue \(blocksize*512\) to).25 F F3(stdout)2.503 E F0 5.003(.I).68 G
+2.503(ft)-5.003 G .003(his output is redirected)-2.503 F
+(to a location \214le)144 496.8 Q F3(loc\214le)2.5 E F0 2.5(,t).18 G
+(his \214le may be used by)-2.5 E F2(dds2tar\(1\))2.5 E F0
+(to access archi)2.5 E -.15(ve)-.25 G 2.5(so).15 G 2.5(nt)-2.5 G(ape.)
+-2.5 E F2(label)108 520.8 Q F0 .217
+(If the current tape position is the be)15.44 F .217
+(ginning of an archi)-.15 F .517 -.15(ve a)-.25 H .217(nd the archi).15
+F .517 -.15(ve i)-.25 H 2.717(sl).15 G(abeled,)-2.717 E F2(mt-dds)2.717
+E F0(writes)2.717 E(the label to stdout and mo)144 532.8 Q -.15(ve)-.15
+G 2.5(st).15 G(he tape back to the current position \(or back o)-2.5 E
+-.15(ve)-.15 G 2.5(rt).15 G(he \214lemark\).)-2.5 E F2(ts)108 556.8 Q F0
+.217(If the current tape position is the be)28.78 F .217
+(ginning of an archi)-.15 F .517 -.15(ve a)-.25 H .217(nd the archi).15
+F .517 -.15(ve i)-.25 H 2.717(sl).15 G(abeled,)-2.717 E F2(mt-dds)2.717
+E F0(writes)2.718 E .847(the timestamp in octal format to stdout and mo)
+144 568.8 R -.15(ve)-.15 G 3.347(st).15 G .847
+(he tape back to the current position \(or back)-3.347 F -.15(ove)144
+580.8 S 3.617(rt).15 G 1.117(he \214lemark\).)-3.617 F 1.117
+(If you are using only one computer)6.117 F 3.617(,t)-.4 G 1.117
+(he timestamp can be used as a unique)-3.617 F(archi)144 592.8 Q .3 -.15
+(ve i)-.25 H(denti\214er).15 E(.)-.55 E F2(-b #)108 616.8 Q F0 .746
+(Specify the block size)19.61 F F3(#)3.246 E F0 -.25(va)3.246 G .745
+(lue that is used as a def).25 F .745(ault for the written v)-.1 F .745
+(alue with the)-.25 F F2 .745(mt-dds tell)3.245 F F0 .633
+(command \(see abo)144 628.8 R -.15(ve)-.15 G 3.133(\). Also).15 F .633
+(the internal b)3.133 F(uf)-.2 E .633
+(fer size is speci\214ed with this option which is used to)-.25 F .263(\
+read one block in order to get the block size of the current tape block\
+. So specify the block size of)144 640.8 R(the archi)144 652.8 Q .3 -.15
+(ve o)-.25 H 2.5(ral).15 G(ar)-2.5 E(ger number)-.18 E(.)-.55 E F2
+(other options)87 676.8 Q(-f)108 688.8 Q F3(de)2.85 E(vice)-.15 E F0(De)
+144 700.8 Q .791(vice of the tape archi)-.25 F 1.091 -.15(ve \()-.25 H
+(def).15 E .791(ault is /de)-.1 F 3.291(v/rmt0\). Must)-.25 F .792
+(be a character special \214le connected to a)3.291 F(dds tape de)144
+712.8 Q(vice.)-.25 E 220.25(2.4 1)299.75 768 R EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 374.4(mt-dds\(1L\) mt-dds\(1L\))72 48 R/F1 10
+/Times-Bold@0 SF(-V)108 84 Q F0(,)A F1(--v)A(ersion)-.1 E F0
+(Print the v)144 96 Q(ersion number of)-.15 E F1(mt-dds)2.5 E F0
+(to stderr and e)2.5 E(xit immediately)-.15 E(.)-.65 E F1(--help)108 120
+Q F0(print some screens of online help with e)11 E
+(xamples through a pager and e)-.15 E(xit immediately)-.15 E(.)-.65 E/F2
+9/Times-Bold@0 SF(EXAMPLES)72 144 Q F1(Example 1:)108 156 Q F0
+(checking the compression mode of the def)2.5 E(ault tape de)-.1 E(vice)
+-.25 E(mt-dds comp-query)158 168 Q F1(Example 2:)108 192 Q F0
+(Write the location information as)2.5 E F1(dds2tar)2.5 E F0
+(command line options to stdout.)2.5 E(mt-dds)158 204 Q F2(ENVIR)72 240
+Q(ONMENT)-.27 E F0(The en)108 252 Q(vironment v)-.4 E(ariable)-.25 E F1
+-.9(TA)2.5 G(PE).9 E F0 -.15(ove)2.5 G(rrides the def).15 E
+(ault tape de)-.1 E(vice /de)-.25 E(v/rmt0.)-.25 E -1.06 -.92(PA G)108
+276 T(ER).92 E .914(The en)144 288 R .914(vironment v)-.4 F(ariable)-.25
+E F1 -1.57 -.74(PA G)3.414 H(ER).74 E F0 -.15(ove)3.414 G .914
+(rrides the b).15 F .913
+(uiltin pager command \("/bin/more"\) to display)-.2 F
+(the output of the)144 300 Q F1(--help)2.5 E F0(option.)2.5 E F2
+(SEE ALSO)72 324 Q F0(dds2tar\(1\), dds2inde)108 336 Q
+(x\(1\), mt\(1\), tar\(1\))-.15 E F2(HIST)72 360 Q(OR)-.162 E(Y)-.315 E
+F0(This program w)108 372 Q(as created in conjunction with dds2tar)-.1 E
+(.)-.55 E F2 -.45(AU)72 396 S(THOR).45 E F0(J"or)108 408 Q 3.028(gW)-.18
+G .528(eule \(weule@cs.uni-duesseldorf.de\), Phone +49 211 751409.)
+-3.828 F .528(This softw)5.528 F .529(are is a)-.1 F -.25(va)-.2 G .529
+(ilable at ftp.uni-).25 F(duesseldorf.de:/pub/unix/apollo)108 420 Q
+220.25(2.4 2)299.75 768 R EP
+%%Trailer
+end
+%%EOF
--- /dev/null
+#!/bin/csh
+#
+# Determine the Verndor of a device
+#
+# csh-Example:
+#
+# <1>scsi_vendor
+# Disks: SEAGATE SAMSUNG
+# Cdroms: TOSHIBA PHILIPS
+# Tapes: HP
+# <2>scsi_vendor disk
+# SEAGATE SAMSUNG
+# <383>scsi_vendor cd
+# TOSHIBA PHILIPS
+# <3>scsi_vendor tape
+# HP
+# <4>scsi_vendor tape 1
+# HP
+# <5>scsi_vendor dsik 1
+# <6>scsi_vendor disk 1
+# SEAGATE
+# <7>scsi_vendor disk 2
+# SAMSUNG
+#
+set s = ( ) ;
+set c = ( ) ;
+set d = ( ) ;
+set x = ( `grep '^ ' /proc/scsi/scsi | cut -c3-18` )
+set o = '' ;
+set v = '' ;
+foreach i ( $x )
+ if ( "$o" == 'Vendor:' ) set v = $i ;
+ if ( "$o" == 'Type:' && "$i" == 'Sequenti' ) set s = ( $s $v );
+ if ( "$o" == 'Type:' && "$i" == 'CD-ROM' ) set c = ( $c $v );
+ if ( "$o" == 'Type:' && "$i" == 'Direct-A' ) set d = ( $d $v );
+ set o = $i ;
+end
+if ( $# == 0 ) then
+ echo Disks: $d
+ echo Cdroms: $c
+ echo Tapes: $s
+ exit 0 ;
+endif
+if ( $# == 1 ) then
+ set v = '' ;
+ if ( $1 == disk ) then
+ echo $d
+ endif
+ if ( $1 == cd ) then
+ echo $c
+ endif
+ if ( $1 == tape ) then
+ echo $s
+ endif
+ exit 0 ;
+endif
+if ( $# == 2 ) then
+ set v = '' ;
+ if ( $1 == disk && $#d >= $2 ) then
+ set v = $d[$2] ;
+ endif
+ if ( $1 == cd && $#c >= $2 ) then
+ set v = $c[$2] ;
+ endif
+ if ( $1 == tape && $#s >= $2 ) then
+ set v = $s[$2] ;
+ endif
+ echo $v
+ exit 0 ;
+endif
+if ( "$v" == "$3" ) then
+ exit 2 ;
+endif
+exit 1 ;
+
--- /dev/null
+Michael Riepe (riepe@ifwsn4.ifw.uni-hannover.de) has send me a patch
+to support sparse files with tar on Linux boxes.
+
+I did'nt have any experience with it and unfortunately dds2tar doesn't support
+sparse files. But if you are familar with patching tar, you may decide
+to include this patch also.
+
+Please send comments on that patch to Michael. J"org.
+
--- /dev/null
+diff -ru tar-1.11.2/create.c tar-1.11.2.1/create.c
+--- tar-1.11.2/create.c Thu Mar 25 19:32:31 1993
++++ tar-1.11.2.1/create.c Wed Oct 26 01:11:39 1994
+@@ -380,7 +380,7 @@
+
+ header_moved = 0;
+
+-#ifdef BSD42
++#if defined(BSD42) || defined(__linux__)
+ if (f_sparse_files)
+ {
+ /*
--- /dev/null
+diff -ru tar-1.11.2/ChangeLog tar-1.11.2.1/ChangeLog
+--- tar-1.11.2/ChangeLog Thu Mar 25 19:54:56 1993
++++ tar-1.11.2.1/ChangeLog Mon Oct 3 21:07:15 1994
+@@ -1,3 +1,16 @@
++Sat Jun 19 14:00:00 1994 J"org Weule (weule@cs.uni-duesseldorf.de)
++
++ * version.c: version 1.11.2 (added --record-file)
++
++ * create.c: print header before incrementing the record #
++
++ * tar.c: inserted the option --record-file
++
++ * buffer.c: opens the record file
++
++ * list.c: writes the record information to rec_files instead of
++ msg_file
++
+ Thu Mar 25 13:32:40 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
+
+ * version.c: Released version 1.11.2.
+diff -ru tar-1.11.2/buffer.c tar-1.11.2.1/buffer.c
+--- tar-1.11.2/buffer.c Fri Mar 19 21:05:11 1993
++++ tar-1.11.2.1/buffer.c Thu Feb 9 23:01:33 1995
+@@ -62,6 +62,8 @@
+ /* Either stdout or stderr: The thing we write messages (standard msgs, not
+ errors) to. Stdout unless we're writing a pipe, in which case stderr */
+ FILE *msg_file = stdout;
++FILE *rec_file = stdout;
++char *rec_file_name = NULL ;
+
+ #define STDIN 0 /* Standard input file descriptor */
+ #define STDOUT 1 /* Standard output file descriptor */
+@@ -115,7 +117,7 @@
+ /*
+ * Record number of the start of this block of records
+ */
+-long baserec;
++long baserec = 0 ;
+
+ /*
+ * Error recovery stuff
+@@ -534,7 +536,44 @@
+ open_archive (reading)
+ int reading;
+ {
+- msg_file = f_exstdout ? stderr : stdout;
++ time_t start_time = time(0);
++ rec_file = msg_file = f_exstdout ? stderr : stdout;
++ if ( rec_file_name != NULL )
++ {
++#define INSERT_TIMESTAMP
++#ifdef INSERT_TIMESTAMP
++ /*
++ * A record-file name with '%T' will be expanded with a decimal
++ * value for the timestamp of the archive. This is the time value
++ * stored in the label record.
++ * If you are using only one computer, this should be a unique number.
++ * You are able to create different rec-files for all your archives,
++ * as well as finding the index of your archive in a reliable way.
++ *
++ * Another way would be to let us set the timestamp by another option.
++ * tar --timestamp <ts-number> ...
++ */
++ char rfn[256];
++ if ( reading == 0 ) {
++ char*p= rec_file_name ;
++ int i = 0 ;
++ int n;
++ while ( p[0] != '\0' ) {
++ if ( p[0] == '%' && p[1] == 'T' ) {
++ i += sprintf(rfn+i,"%d",start_time), p += 2 ;
++ } else { rfn[i++] = *p++ ; }
++ }
++ rfn[i] = '\0' ;
++ } else strcpy(rfn,rec_file_name);
++#else
++ char*rfn=rec_file_name;
++#endif
++ if ( ( rec_file = fopen(rfn,"w")) == NULL )
++ {
++ fprintf(rec_file,"Cannot open %s.\n",rec_file_name);
++ exit(1);
++ }
++ }
+
+ if (blocksize == 0)
+ {
+@@ -542,6 +581,19 @@
+ exit (EX_ARGSBAD);
+ }
+
++ if ( ( f_sayblock ) && ( f_volhdr ) )
++ {
++ fprintf(rec_file,
++ "loc timestamp is %d \n",
++ start_time);
++ }
++ if ( f_sayblock && (blocksize != 10240) )
++ {
++ fprintf(rec_file,
++ "loc block length is %d bytes = %d * 512 bytes \n",
++ blocksize,blocksize>>9);
++ }
++
+ if (n_ar_files == 0)
+ {
+ msg ("No archive name given, what should I do?");
+@@ -648,6 +700,38 @@
+ setmode (archive, O_BINARY);
+ #endif
+
++#if defined(MTTELL)
++ /* Prints the file number of the archive */
++ if ( f_sayblock )
++ {
++ struct mtget get ;
++ int i ;
++ i = ioctl(archive,MTIOCGET,&get);
++ if (( i == 0 ) && ( get.mt_fileno >= 0 ))
++ {
++ fprintf(rec_file,
++ "loc number of the file is %d \n",
++ get.mt_fileno );
++ }
++ }
++#endif
++
++#if defined(MTIOCPOS)
++ /* Prints the tape block number on every Linux SCSI-device */
++ if ( f_sayblock )
++ {
++ struct mtpos pos ;
++ int i ;
++ i = ioctl(archive,MTIOCPOS,&pos);
++ if ( i == 0 )
++ {
++ fprintf(rec_file,
++ "loc number of the first block is %d\n",
++ pos.mt_blkno );
++ }
++ }
++#endif
++
+ if (reading)
+ {
+ ar_last = ar_block; /* Set up for 1st block = # 0 */
+@@ -700,7 +784,7 @@
+ strcpy (ar_block->header.arch_name, f_volhdr);
+ current_file_name = ar_block->header.arch_name;
+ ar_block->header.linkflag = LF_VOLHDR;
+- to_oct (time (0), 1 + 12, ar_block->header.mtime);
++ to_oct (start_time, 1 + 12, ar_block->header.mtime);
+ finish_header (ar_block);
+ /* ar_record++; */
+ }
+diff -ru tar-1.11.2/create.c tar-1.11.2.1/create.c
+--- tar-1.11.2/create.c Thu Mar 25 19:32:31 1993
++++ tar-1.11.2.1/create.c Mon Oct 3 21:06:01 1994
+@@ -1340,7 +1340,10 @@
+ to_oct ((long) sum, 8, header->header.chksum);
+ header->header.chksum[6] = '\0'; /* Zap the space */
+
+- userec (header);
++ /* print header first to get the same output with 'tar -tvR'
++ * and 'tar -cvR'
++ */
++ /* userec (header); */
+
+ if (f_verbose)
+ {
+@@ -1353,6 +1356,8 @@
+ head_standard = f_standard;
+ print_header ();
+ }
++
++ userec (header);
+
+ return;
+ }
+diff -ru tar-1.11.2/list.c tar-1.11.2.1/list.c
+--- tar-1.11.2/list.c Tue Mar 16 20:56:01 1993
++++ tar-1.11.2.1/list.c Wed Oct 12 14:01:01 1994
+@@ -48,6 +48,7 @@
+ #include "port.h"
+
+ extern FILE *msg_file;
++extern FILE *rec_file;
+
+ long from_oct (); /* Decode octal number */
+ void demode (); /* Print file mode */
+@@ -563,7 +564,7 @@
+ extern long baserec;
+
+ if (f_sayblock)
+- fprintf (msg_file, "rec %10d: ", baserec + (ar_record - ar_block));
++ fprintf (rec_file, "rec %10d: ", baserec + (ar_record - ar_block));
+ /* annofile(msg_file, (char *)NULL); */
+
+ if (f_verbose <= 1)
+@@ -574,7 +575,7 @@
+ name = quote_copy_string (current_file_name);
+ if (name == 0)
+ name = current_file_name;
+- fprintf (msg_file, "%s\n", name);
++ fprintf (rec_file, "%s\n", name);
+ if (name != current_file_name)
+ free (name);
+ }
+@@ -585,6 +586,11 @@
+ switch (head->header.linkflag)
+ {
+ case LF_VOLHDR:
++ /* dirty bug fix to display the header processing
++ * tar cvvf /dev/null --label 'hello world' blah...
++ * J"org Weule weule@cs.uni-duesseldorf.de
++ */
++ hstat.st_mtime = from_oct(1 + 12 , head->header.mtime);
+ modes[0] = 'V';
+ break;
+
+@@ -689,7 +695,7 @@
+ name = quote_copy_string (current_file_name);
+ if (!name)
+ name = current_file_name;
+- fprintf (msg_file, "%s %s/%s %*s%s %s %s %s",
++ fprintf (rec_file, "%s %s/%s %*s%s %s %s %s",
+ modes,
+ user,
+ group,
+@@ -707,7 +713,7 @@
+ name = quote_copy_string (current_link_name);
+ if (!name)
+ name = current_link_name;
+- fprintf (msg_file, " -> %s\n", name);
++ fprintf (rec_file, " -> %s\n", name);
+ if (name != current_link_name)
+ free (name);
+ break;
+@@ -716,13 +722,13 @@
+ name = quote_copy_string (current_link_name);
+ if (!name)
+ name = current_link_name;
+- fprintf (msg_file, " link to %s\n", current_link_name);
++ fprintf (rec_file, " link to %s\n", current_link_name);
+ if (name != current_link_name)
+ free (name);
+ break;
+
+ default:
+- fprintf (msg_file, " unknown file type '%c'\n",
++ fprintf (rec_file, " unknown file type '%c'\n",
+ head->header.linkflag);
+ break;
+
+@@ -735,23 +741,23 @@
+ case LF_FIFO:
+ case LF_CONTIG:
+ case LF_DUMPDIR:
+- putc ('\n', msg_file);
++ putc ('\n', rec_file);
+ break;
+
+ case LF_VOLHDR:
+- fprintf (msg_file, "--Volume Header--\n");
++ fprintf (rec_file, "--Volume Header--\n");
+ break;
+
+ case LF_MULTIVOL:
+- fprintf (msg_file, "--Continued at byte %ld--\n", from_oct (1 + 12, head->header.offset));
++ fprintf (rec_file, "--Continued at byte %ld--\n", from_oct (1 + 12, head->header.offset));
+ break;
+
+ case LF_NAMES:
+- fprintf (msg_file, "--Mangled file names--\n");
++ fprintf (rec_file, "--Mangled file names--\n");
+ break;
+ }
+ }
+- fflush (msg_file);
++ fflush (rec_file);
+ }
+
+ /*
+@@ -774,12 +780,12 @@
+ demode ((unsigned) mode, modes + 1);
+
+ if (f_sayblock)
+- fprintf (msg_file, "rec %10d: ", baserec + (ar_record - ar_block));
++ fprintf (rec_file, "rec %10d: ", baserec + (ar_record - ar_block));
+ /* annofile(msg_file, (char *)NULL); */
+ name = quote_copy_string (pathname);
+ if (!name)
+ name = pathname;
+- fprintf (msg_file, "%s %*s %.*s\n",
++ fprintf (rec_file, "%s %*s %.*s\n",
+ modes,
+ ugswidth + DATEWIDTH,
+ "Creating directory:",
+diff -ru tar-1.11.2/tar.c tar-1.11.2.1/tar.c
+--- tar-1.11.2/tar.c Wed Mar 17 16:30:46 1993
++++ tar-1.11.2.1/tar.c Thu Oct 13 00:48:14 1994
+@@ -71,6 +71,8 @@
+
+
+ extern FILE *msg_file;
++extern FILE *rec_file;
++extern char *rec_file_name;
+
+ int check_exclude ();
+ void add_exclude ();
+@@ -122,6 +124,7 @@
+ {"null", 0, 0, 16},
+ {"directory", 1, 0, 'C'},
+ {"record-number", 0, &f_sayblock, 1},
++ {"record-file",1,0,19},
+ {"files-from", 1, 0, 'T'},
+ {"label", 1, 0, 'V'},
+ {"exclude-from", 1, 0, 'X'},
+@@ -361,6 +364,11 @@
+ f_compressprog = optarg;
+ break;
+
++ case 19:
++ rec_file_name = optarg ;
++ f_sayblock++; /* Print block #s for debug */
++ break;
++
+ case 'g': /* We are making a GNU dump; save
+ directories at the beginning of
+ the archive, and include in each
+@@ -731,6 +739,7 @@
+ ", stdout); /* KLUDGE */
+ fputs ("\
+ -R, --record-number show record number within archive with each message\n\
++--record-file print the record information to file, enable -R\n\
+ --remove-files remove files after adding them to the archive\n\
+ -s, --same-order,\n\
+ --preserve-order list of names to extract is sorted to match archive\n\
+diff -ru tar-1.11.2/version.c tar-1.11.2.1/version.c
+--- tar-1.11.2/version.c Thu Mar 25 19:35:25 1993
++++ tar-1.11.2.1/version.c Mon Oct 3 16:01:59 1994
+@@ -1 +1 @@
+-char version_string[] = "GNU tar version 1.11.2";
++char version_string[] = "GNU tar version 1.11.2 (added --record-file)";
--- /dev/null
+diff -ru tar-1.11.8/lib/rx.h tar-1.11.8.1/lib/rx.h
+--- tar-1.11.8/lib/rx.h Fri May 5 14:17:10 1995
++++ tar-1.11.8.1/lib/rx.h Fri May 5 14:17:10 1995
+@@ -1382,7 +1382,7 @@
+
+ /* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+- If not smt, then `\{...\}' defines an interval. */
++ If not set, then `\{...\}' defines an interval. */
+ #define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+ /* If this bit is set, (...) defines a group, and \( and \) are literals.
+diff -ru tar-1.11.8/src/buffer.c tar-1.11.8.1/src/buffer.c
+--- tar-1.11.8/src/buffer.c Mon May 29 02:26:27 1995
++++ tar-1.11.8.1/src/buffer.c Mon Feb 5 20:20:19 1996
+@@ -46,6 +46,7 @@
+ /* Where we write messages (standard messages, not errors) to. Stdout
+ unless we're writing a pipe, in which case stderr. */
+ FILE *stdlis;
++FILE *stdrec;
+
+ #define STDIN 0 /* standard input file descriptor */
+ #define STDOUT 1 /* standard output file descriptor */
+@@ -77,7 +78,7 @@
+ static int childpid = 0;
+
+ /* Record number of the start of this block of records */
+-long baserec;
++long baserec = 0 ;
+
+ /* Error recovery stuff */
+ static int r_error_count;
+@@ -520,11 +521,64 @@
+ void
+ open_archive (int reading)
+ {
+- stdlis = flag_exstdout ? stderr : stdout;
++ time_t start_time = time(0) ;
++ stdrec = stdlis = flag_exstdout ? stderr : stdout;
++ if ( record_file_name != NULL )
++ {
++#define INSERT_TIMESTAMP
++#ifdef INSERT_TIMESTAMP
++ /*
++ * A record-file name with '%T' will be expanded with a decimal
++ * value for the timestamp of the archive. This is the time value
++ * stored in the label record.
++ * If you are using only one computer, this should be a unique number.
++ * You are able to create different rec-files for all your archives,
++ * as well as finding the index of your archive in a reliable way.
++ *
++ * Another way would be to let us set the timestamp by another option.
++ * tar --timestamp <ts-number> ...
++ */
++ char rfn[256];
++ if ( reading == 0 ) {
++ char*p= record_file_name ;
++ int i = 0 ;
++ int n;
++ while ( p[0] != '\0' ) {
++ if ( p[0] == '%' && p[1] == 'T' ) {
++ /* i += */ sprintf(rfn+i,"%d",start_time);
++ i = strlen(rfn) ;
++ p += 2 ;
++ } else { rfn[i++] = *p++ ; }
++ }
++ rfn[i] = '\0' ;
++ } else strcpy(rfn,record_file_name);
++#else
++ char*rfn=record_file_name;
++#endif
++ if ( ( stdrec = fopen(rfn,"w")) == NULL )
++ {
++ fprintf(stdlis,"Cannot open %s.\n",record_file_name);
++ exit(1);
++ }
++ }
++
+
+ if (blocksize == 0)
+ ERROR ((TAREXIT_FAILURE, 0, _("Invalid value for blocksize")));
+
++ if ( ( flag_sayblock ) && ( flag_volhdr ) )
++ {
++ fprintf(stdrec,
++ "loc timestamp is %d \n",
++ start_time);
++ }
++ if ( flag_sayblock && (blocksize != 10240) )
++ {
++ fprintf(stdrec,
++ "loc block length is %d bytes = %d * 512 bytes \n",
++ blocksize,blocksize>>9);
++ }
++
+ if (archive_names == 0)
+ ERROR ((TAREXIT_FAILURE, 0,
+ _("No archive name given, what should I do?")));
+@@ -618,6 +672,38 @@
+ setmode (archive, O_BINARY);
+ #endif
+
++#if defined(MTIOCGET)
++ /* Prints the file number of the archive */
++ if ( flag_sayblock )
++ {
++ struct mtget get ;
++ int i ;
++ i = ioctl(archive,MTIOCGET,&get);
++ if (( i == 0 ) && ( get.mt_fileno >= 0 ))
++ {
++ fprintf(stdrec,
++ "loc number of the file is %d \n",
++ get.mt_fileno );
++ }
++ }
++#endif
++
++#if defined(MTIOCPOS)
++ /* Prints the tape block number on every Linux SCSI-device */
++ if ( flag_sayblock )
++ {
++ struct mtpos pos ;
++ int i ;
++ i = ioctl(archive,MTIOCPOS,&pos);
++ if ( i == 0 )
++ {
++ fprintf(stdrec,
++ "loc number of the first block is %d\n",
++ pos.mt_blkno );
++ }
++ }
++#endif
++
+ if (reading)
+ {
+ ar_last = ar_block; /* set up for 1st block = # 0 */
+@@ -666,7 +752,7 @@
+ assign_string (¤t_file_name, ar_block->header.arch_name);
+
+ ar_block->header.linkflag = LF_VOLHDR;
+- to_oct (time (0), 1 + 12, ar_block->header.mtime);
++ to_oct (start_time , 1 + 12, ar_block->header.mtime);
+ finish_header (ar_block);
+ #if 0
+ ar_record++;
+@@ -727,7 +813,7 @@
+ if (err != blocksize && !flag_multivol)
+ writeerror (err);
+ else if (flag_totals)
+- tot_written += blocksize;
++ tot_written += blocking;
+
+ if (err > 0)
+ bytes_written += err;
+@@ -816,7 +902,7 @@
+ if (err != blocksize)
+ writeerror (err);
+ else if (flag_totals)
+- tot_written += blocksize;
++ tot_written += blocking;
+
+
+ bytes_written = blocksize;
+diff -ru tar-1.11.8/src/create.c tar-1.11.8.1/src/create.c
+--- tar-1.11.8/src/create.c Sat Jun 17 23:08:13 1995
++++ tar-1.11.8.1/src/create.c Sun Dec 1 01:55:08 1996
+@@ -315,7 +315,10 @@
+ to_oct ((long) sum, 8, header->header.chksum);
+ header->header.chksum[6] = '\0'; /* zap the space */
+
+- userec (header);
++ /* print header first to get the same output with 'tar -tvR'
++ * and 'tar -cvR'
++ */
++ /* userec (header); */
+
+ if (flag_verbose)
+ {
+@@ -327,6 +330,8 @@
+ head_standard = flag_standard;
+ print_header ();
+ }
++
++ userec (header) ;
+
+ return;
+ }
+diff -ru tar-1.11.8/src/extract.c tar-1.11.8.1/src/extract.c
+--- tar-1.11.8/src/extract.c Sun Jun 11 15:40:21 1995
++++ tar-1.11.8.1/src/extract.c Sun Dec 1 01:55:28 1996
+@@ -684,6 +684,7 @@
+ case LF_LONGNAME:
+ case LF_LONGLINK:
+ ERROR ((0, 0, _("Visible long name error")));
++ print_header();
+ skip_file ((long) hstat.st_size);
+ break;
+ }
+diff -ru tar-1.11.8/src/list.c tar-1.11.8.1/src/list.c
+--- tar-1.11.8/src/list.c Wed May 3 05:28:17 1995
++++ tar-1.11.8.1/src/list.c Sun Dec 1 16:22:12 1996
+@@ -200,7 +200,7 @@
+ if (written > size)
+ written = size;
+ errno = 0;
+- check = fwrite (data, sizeof (char), written, stdlis);
++ check = fwrite (data, sizeof (char), written, stdrec);
+ userec ((union record *) (data + written - 1));
+ if (check != written)
+ {
+@@ -213,8 +213,8 @@
+ if (flag_multivol)
+ assign_string (&save_name, NULL);
+ saverec (NULL); /* unsave it */
+- fputc ('\n', stdlis);
+- fflush (stdlis);
++ fputc ('\n', stdrec);
++ fflush (stdrec);
+ return;
+
+ }
+@@ -353,6 +353,8 @@
+ longp = ((header->header.linkflag == LF_LONGNAME)
+ ? &next_long_name
+ : &next_long_link);
++ assign_string (¤t_file_name, header->header.arch_name);
++ print_header();
+
+ userec (header);
+ if (*longp)
+@@ -533,9 +535,9 @@
+ char *name;
+
+ if (flag_sayblock)
+- fprintf (stdlis, _("rec %10ld: "), baserec + (ar_record - ar_block));
++ fprintf (stdrec, _("rec %10ld: "), baserec + (ar_record - ar_block));
+ #if 0
+- annofile (stdlis, (char *) NULL);
++ annofile (stdrec, (char *) NULL);
+ #endif
+
+ if (flag_verbose <= 1)
+@@ -547,11 +549,11 @@
+
+ if (quoted_name)
+ {
+- fprintf (stdlis, "%s\n", quoted_name);
++ fprintf (stdrec, "%s\n", quoted_name);
+ free (quoted_name);
+ }
+ else
+- fprintf (stdlis, "%s\n", current_file_name);
++ fprintf (stdrec, "%s\n", current_file_name);
+ }
+ else
+ {
+@@ -562,6 +564,11 @@
+ switch (head->header.linkflag)
+ {
+ case LF_VOLHDR:
++ /* dirty bug fix to display the header processing
++ * tar cvvf /dev/null --label 'hello world' blah...
++ * J"org Weule weule@cs.uni-duesseldorf.de
++ */
++ hstat.st_mtime = from_oct(1 + 12 , head->header.mtime);
+ modes[0] = 'V';
+ break;
+
+@@ -574,8 +581,13 @@
+ break;
+
+ case LF_LONGNAME:
++ /*ERROR ((0, 0, _("Visible longname error")));*/
++ modes[0] = 'L';
++ break;
++
+ case LF_LONGLINK:
+- ERROR ((0, 0, _("Visible longname error")));
++ /*ERROR ((0, 0, _("Visible longname error")));*/
++ modes[0] = 'K';
+ break;
+
+ case LF_SPARSE:
+@@ -663,18 +675,18 @@
+ if (pad > ugswidth)
+ ugswidth = pad;
+
+- fprintf (stdlis, "%s %s/%s %*s%s %s %s",
++ fprintf (stdrec, "%s %s/%s %*s%s %s %s",
+ modes, user, group, ugswidth - pad, "",
+ size, timestamp + 4, timestamp + 20);
+
+ name = quote_copy_string (current_file_name);
+ if (name)
+ {
+- fprintf (stdlis, " %s", name);
++ fprintf (stdrec, " %s", name);
+ free (name);
+ }
+ else
+- fprintf (stdlis, " %s", current_file_name);
++ fprintf (stdrec, " %s", current_file_name);
+
+ switch (head->header.linkflag)
+ {
+@@ -682,26 +694,26 @@
+ name = quote_copy_string (current_link_name);
+ if (name)
+ {
+- fprintf (stdlis, " -> %s\n", name);
++ fprintf (stdrec, " -> %s\n", name);
+ free (name);
+ }
+ else
+- fprintf (stdlis, " -> %s\n", current_link_name);
++ fprintf (stdrec, " -> %s\n", current_link_name);
+ break;
+
+ case LF_LINK:
+ name = quote_copy_string (current_link_name);
+ if (name)
+ {
+- fprintf (stdlis, _(" link to %s\n"), name);
++ fprintf (stdrec, _(" link to %s\n"), name);
+ free (name);
+ }
+ else
+- fprintf (stdlis, _(" link to %s\n"), current_link_name);
++ fprintf (stdrec, _(" link to %s\n"), current_link_name);
+ break;
+
+ default:
+- fprintf (stdlis, _(" unknown file type `%c'\n"),
++ fprintf (stdrec, _(" unknown file type `%c'\n"),
+ head->header.linkflag);
+ break;
+
+@@ -714,24 +726,32 @@
+ case LF_FIFO:
+ case LF_CONTIG:
+ case LF_DUMPDIR:
+- putc ('\n', stdlis);
++ putc ('\n', stdrec);
++ break;
++
++ case LF_LONGNAME:
++ fprintf (stdrec, _("--Long Name--\n"));
++ break;
++
++ case LF_LONGLINK:
++ fprintf (stdrec, _("--Long Link--\n"));
+ break;
+
+ case LF_VOLHDR:
+- fprintf (stdlis, _("--Volume Header--\n"));
++ fprintf (stdrec, _("--Volume Header--\n"));
+ break;
+
+ case LF_MULTIVOL:
+- fprintf (stdlis, _("--Continued at byte %ld--\n"),
++ fprintf (stdrec, _("--Continued at byte %ld--\n"),
+ from_oct (1 + 12, head->header.offset));
+ break;
+
+ case LF_NAMES:
+- fprintf (stdlis, _("--Mangled file names--\n"));
++ fprintf (stdrec, _("--Mangled file names--\n"));
+ break;
+ }
+ }
+- fflush (stdlis);
++ fflush (stdrec);
+ }
+
+ /*--------------------------------------------------------------.
+@@ -753,9 +773,9 @@
+ demode ((unsigned) mode, modes + 1);
+
+ if (flag_sayblock)
+- fprintf (stdlis, _("rec %10ld: "), baserec + (ar_record - ar_block));
++ fprintf (stdrec, _("rec %10ld: "), baserec + (ar_record - ar_block));
+ #if 0
+- annofile (stdlis, (char *) NULL);
++ annofile (stdrec, (char *) NULL);
+ #endif
+ name = quote_copy_string (pathname);
+ if (!name)
+diff -ru tar-1.11.8/src/tar.c tar-1.11.8.1/src/tar.c
+--- tar-1.11.8/src/tar.c Sat Jun 17 22:48:32 1995
++++ tar-1.11.8.1/src/tar.c Mon Apr 8 16:54:08 1996
+@@ -860,6 +860,7 @@
+ #define OPTION_VOLNO_FILE 15
+ #define OPTION_COMPRESS_PROG 16
+ #define OPTION_RSH_COMMAND 17
++#define OPTION_RECORD_FILE 18
+
+ /* Some cleanup is made in GNU tar long options. Using old names will send
+ a warning to stderr. */
+@@ -925,6 +926,7 @@
+ {"preserve-permissions", no_argument, NULL, 'p'},
+ {"read-full-blocks", no_argument, NULL, 'B'},
+ {"record-number", no_argument, NULL, 'R'},
++ {"record-file", required_argument, NULL, OPTION_RECORD_FILE},
+ {"remove-files", no_argument, &flag_remove_files, 1},
+ {"rsh-command", required_argument, NULL, OPTION_RSH_COMMAND},
+ {"same-order", no_argument, NULL, 's'},
+@@ -1059,6 +1061,7 @@
+ --checkpoint print directory names while reading the archive\n\
+ --totals print total bytes written while creating archive\n\
+ -R, --record-number show record number within archive with each message\n\
++ --record-file print the record information to file, enable -R\n\
+ -w, --interactive ask for confirmation for every action\n\
+ --confirmation same as -w\n"),
+ stdout);
+@@ -1212,6 +1215,11 @@
+ flag_rsh_command = optarg;
+ break;
+
++ case OPTION_RECORD_FILE:
++ record_file_name = optarg ;
++ flag_sayblock++; /* Print block #s for debug */
++ break;
++
+ case 'g':
+ /* We are making a GNU dump; save directories at the beginning
+ of the archive, and include in each directory its contents. */
+@@ -1626,9 +1634,42 @@
+ break;
+
+ case COMMAND_CREATE:
++/*
++ * Comment the next line out if you have problems. Joerg Weule
++ */
++#define PRINT_TROUPUT
++#ifdef PRINT_TROUPUT
++ start_time = time(0);
++ create_archive ();
++ if (flag_totals) {
++ time_t end_time = time(0);
++ double sec = end_time - start_time ;
++ double t = ((double)tot_written) * RECORDSIZE ;
++ fprintf (stderr, _("Total bytes written: %.0f"),t);
++ if ( t >= 1e9 ) fprintf(stderr, _(" (%3.1f Gb)"),t/1e9 ); else
++ if ( t >= 1e6 ) fprintf(stderr, _(" (%3.1f Mb)"),t/1e6 ); else
++ if ( t >= 1024 ) fprintf(stderr, _(" (%3.1f Kb)"),t/1024 );
++ fprintf(stderr,"\n");
++ if ( sec > 0.1 ){
++ long s, m, h = sec ;
++ m = h ;
++ h /= 3600 ;
++ m -= h * 3600 ;
++ s = m ;
++ m /= 60 ;
++ s -= m / 60 ;
++ fprintf (stderr, _("Elapsed time: %02d:%02d:%02d, %g sec\n"), h,m,s,sec);
++ if ( !flag_multivol)
++ fprintf (stderr, _("Throughput per second: %.0fKb/sec\n"),
++ t/sec/1024);
++ }
++ }
++#else
+ create_archive ();
+ if (flag_totals)
+- fprintf (stderr, _("Total bytes written: %d\n"), tot_written);
++ fprintf (stderr, _("Total bytes written: %g\n")),
++ ((double)tot_written) * RECORDSIZE );
++#endif
+ break;
+
+ case COMMAND_EXTRACT:
+diff -ru tar-1.11.8/src/tar.h tar-1.11.8.1/src/tar.h
+--- tar-1.11.8/src/tar.h Sat Jun 17 20:36:49 1995
++++ tar-1.11.8.1/src/tar.h Mon Feb 5 20:19:19 1996
+@@ -183,6 +183,9 @@
+ int numbytes;
+ };
+
++/* Time of writing. */
++GLOBAL time_t start_time;
++
+ /* Start of block of archive. */
+ GLOBAL union record *ar_block;
+
+@@ -207,6 +210,9 @@
+ /* File containing names to work on. */
+ GLOBAL const char *namefile_name;
+
++/* File to write record information to. */
++GLOBAL char *record_file_name;
++
+ /* \n or \0. */
+ GLOBAL char filename_terminator;
+
+@@ -219,8 +225,8 @@
+ /* Initial size of the sparsearray. */
+ GLOBAL int sp_array_size;
+
+-/* Total written to output. */
+-GLOBAL int tot_written;
++/* Total written to output in records. */
++GLOBAL long int tot_written;
+
+ /* Compiled regex for extract label. */
+ GLOBAL struct re_pattern_buffer *label_pattern;
+@@ -338,6 +344,7 @@
+
+ extern long baserec;
+ extern FILE *stdlis;
++extern FILE *stdrec;
+ extern char *save_name;
+ extern long save_sizeleft;
+ extern long save_totsize;
--- /dev/null
+diff -ru tar-1.12/src/buffer.c tar-1.12.1/src/buffer.c
+--- tar-1.12/src/buffer.c Fri Apr 25 15:48:46 1997
++++ tar-1.12.1/src/buffer.c Fri Jul 3 12:46:24 1998
+@@ -55,6 +55,7 @@
+
+ static tarlong total_written; /* bytes written on all volumes */
+ static tarlong bytes_written; /* bytes written on this volume */
++static time_t start_time ;
+
+ /* FIXME: The following four variables should ideally be static to this
+ module. However, this cannot be done yet, as update.c uses the first
+@@ -71,6 +72,7 @@
+ /* Where we write list messages (not errors, not interactions) to. Stdout
+ unless we're writing a pipe, in which case stderr. */
+ FILE *stdlis;
++FILE *stdrec;
+
+ static void backspace_output PARAMS ((void));
+ static int new_volume PARAMS ((enum access_mode));
+@@ -160,6 +162,36 @@
+ fprintf (stderr, _("Total bytes written: "));
+ print_tarlong (total_written, stderr);
+ fprintf (stderr, "\n");
++#define PRINT_TROUPUT
++#ifdef PRINT_TROUPUT
++/*
++ * Comment the next line out if you have problems. Joerg Weule
++ */
++ {
++ time_t end_time = time(0);
++ double sec = end_time - start_time ;
++ double t = ((double)total_written) ;
++ fprintf (stderr, _("Total bytes written: %.0f"),t);
++ if ( t >= 1e9 ) fprintf(stderr, _(" (%3.1f Gb)"),t/1e9 ); else
++ if ( t >= 1e6 ) fprintf(stderr, _(" (%3.1f Mb)"),t/1e6 ); else
++ if ( t >= 1024 ) fprintf(stderr, _(" (%3.1f Kb)"),t/1024 );
++ fprintf(stderr,"\n");
++ if ( sec > 0.1 ){
++ long s, m, h = sec ;
++ m = h ;
++ h /= 3600 ;
++ m -= h * 3600 ;
++ s = m ;
++ m /= 60 ;
++ s -= m / 60 ;
++ fprintf (stderr, _("Elapsed time: %02d:%02d:%02d, %g sec\n"), h,m,s,sec);
++ if ( NULL == volume_label_option )
++ fprintf (stderr, _("Throughput per second: %.0fKb/sec\n"),
++ t/sec/1024);
++ }
++ }
++#endif
++
+ }
+
+ /*--------------------------------------------------------.
+@@ -669,6 +701,7 @@
+ {
+ int backed_up_flag = 0;
+
++ start_time = time(0) ;
+ stdlis = to_stdout_option ? stderr : stdout;
+
+ if (record_size == 0)
+@@ -823,6 +856,101 @@
+ setmode (archive, O_BINARY);
+ #endif
+
++ stdrec = stdlis ;
++ if ( record_file_name != NULL )
++ {
++#define INSERT_TIMESTAMP
++#ifdef INSERT_TIMESTAMP
++ /*
++ * A record-file name with '%T' will be expanded with a decimal
++ * value for the timestamp of the archive. This is the time value
++ * stored in the label record.
++ * If you are using only one computer, this should be a unique number.
++ * You are able to create different rec-files for all your archives,
++ * as well as finding the index of your archive in a reliable way.
++ *
++ * Another way would be to let us set the timestamp by another option.
++ * tar --timestamp <ts-number> ...
++ */
++ char rfn[256];
++ if ( subcommand_option == CREATE_SUBCOMMAND ) {
++ char*p= record_file_name ;
++ int i = 0 ;
++ int n;
++ while ( p[0] != '\0' ) {
++ if ( p[0] == '%' && p[1] == 'T' ) {
++ /* i += */ sprintf(rfn+i,"%d",start_time);
++ i = strlen(rfn) ;
++ p += 2 ;
++ } else { rfn[i++] = *p++ ; }
++ }
++ rfn[i] = '\0' ;
++ } else strcpy(rfn,record_file_name);
++#else
++ char*rfn=record_file_name;
++#endif
++ if ( ( stdrec = fopen(rfn,"w")) == NULL )
++ {
++ fprintf(stdlis,"Cannot open %s.\n",record_file_name);
++ exit(1);
++ }
++ }
++
++ if ( ( record_file_name ) && ( volume_label_option ) )
++ {
++ fprintf(stdrec,
++ "loc timestamp is %d \n",
++ start_time);
++ }
++ if ( record_file_name && (record_size != 10240) )
++ {
++ fprintf(stdrec,
++ "loc block length is %d bytes = %d * 512 bytes \n",
++ record_size,record_size>>9);
++ }
++
++
++#if defined(MTIOCGET)
++ /* Prints the file number of the archive */
++ if ( record_file_name )
++ {
++ struct mtget get ;
++ int i ;
++ i = ioctl(archive,MTIOCGET,&get);
++ if (( i == 0 ) && ( get.mt_fileno >= 0 ))
++ {
++ fprintf(stdrec,
++ "loc number of the file is %d \n",
++ get.mt_fileno );
++ }
++ }
++#endif
++
++#if defined(MTIOCPOS)
++ /* Prints the tape block number on every Linux SCSI-device */
++ if ( record_file_name )
++ {
++ struct mtpos pos ;
++ int i ;
++ i = ioctl(archive,MTIOCPOS,&pos);
++ if ( i == 0 )
++ {
++ fprintf(stdrec,
++ "loc number of the first block is %d\n",
++ pos.mt_blkno );
++ }
++ }
++#endif
++ if ( record_file_name )
++ {
++ char *d = malloc(PATH_MAX);
++ if( d && getcwd(d,PATH_MAX) )
++ fprintf(stdrec,
++ "loc current directory is %s\n",
++ d);
++ }
++
++
+ switch (access)
+ {
+ case ACCESS_READ:
+@@ -856,7 +984,7 @@
+ assign_string (¤t_file_name, record_start->header.name);
+
+ record_start->header.typeflag = GNUTYPE_VOLHDR;
+- to_oct (time (0), 1 + 12, record_start->header.mtime);
++ to_oct (start_time, 1 + 12, record_start->header.mtime);
+ finish_header (record_start);
+ #if 0
+ current_block++;
+@@ -958,6 +1086,7 @@
+ memset ((void *) record_start, 0, BLOCKSIZE);
+ sprintf (record_start->header.name, "%s Volume %d", volume_label_option, volno);
+ to_oct (time (0), 1 + 12, record_start->header.mtime);
++ to_oct (start_time, 1 + 12, record_start->header.mtime);
+ record_start->header.typeflag = GNUTYPE_VOLHDR;
+ finish_header (record_start);
+ }
+diff -ru tar-1.12/src/common.h tar-1.12.1/src/common.h
+--- tar-1.12/src/common.h Tue Apr 22 08:31:03 1997
++++ tar-1.12.1/src/common.h Thu Jan 29 01:36:57 1998
+@@ -93,6 +93,9 @@
+ /* Name of this program. */
+ GLOBAL const char *program_name;
+
++/* Time of writing. */
++GLOBAL time_t start_time;
++
+ /* Main command option. */
+
+ enum subcommand
+@@ -141,6 +144,9 @@
+ /* Boolean value. */
+ GLOBAL int block_number_option;
+
++/* Name of the index file */
++GLOBAL char *record_file_name;
++
+ /* Boolean value. */
+ GLOBAL int checkpoint_option;
+
+@@ -335,6 +341,7 @@
+ /* Module buffer.c. */
+
+ extern FILE *stdlis;
++extern FILE *stdrec;
+ extern char *save_name;
+ extern long save_sizeleft;
+ extern long save_totsize;
+diff -ru tar-1.12/src/create.c tar-1.12.1/src/create.c
+--- tar-1.12/src/create.c Fri Apr 25 15:48:48 1997
++++ tar-1.12.1/src/create.c Thu Jan 29 01:00:13 1998
+@@ -329,7 +329,6 @@
+ to_oct ((long) sum, 8, header->header.chksum);
+ header->header.chksum[6] = '\0'; /* zap the space */
+
+- set_next_block_after (header);
+
+ if (verbose_option
+ && header->header.typeflag != GNUTYPE_LONGLINK
+@@ -342,6 +341,8 @@
+ current_format = archive_format;
+ print_header ();
+ }
++
++ set_next_block_after (header);
+ }
+ \f
+ /* Sparse file processing. */
+diff -ru tar-1.12/src/list.c tar-1.12.1/src/list.c
+--- tar-1.12/src/list.c Fri Apr 25 22:16:30 1997
++++ tar-1.12.1/src/list.c Thu Jan 29 11:57:27 1998
+@@ -120,7 +120,7 @@
+
+ case HEADER_ZERO_BLOCK:
+ if (block_number_option)
+- fprintf (stdlis, _("block %10ld: ** Block of NULs **\n"),
++ fprintf (stdrec, _("block %10ld: ** Block of NULs **\n"),
+ current_block_ordinal ());
+
+ set_next_block_after (current_header);
+@@ -131,7 +131,7 @@
+
+ case HEADER_END_OF_FILE:
+ if (block_number_option)
+- fprintf (stdlis, _("block %10ld: ** End of File **\n"),
++ fprintf (stdrec, _("block %10ld: ** End of File **\n"),
+ current_block_ordinal ());
+ break;
+
+@@ -208,7 +208,7 @@
+ if (written > size)
+ written = size;
+ errno = 0; /* FIXME: errno should be read-only */
+- check = fwrite (data_block->buffer, sizeof (char), written, stdlis);
++ check = fwrite (data_block->buffer, sizeof (char), written, stdrec);
+ set_next_block_after ((union block *)
+ (data_block->buffer + written - 1));
+ if (check != written)
+@@ -221,8 +221,8 @@
+ }
+ if (multi_volume_option)
+ assign_string (&save_name, NULL);
+- fputc ('\n', stdlis);
+- fflush (stdlis);
++ fputc ('\n', stdrec);
++ fflush (stdrec);
+ return;
+
+ }
+@@ -367,6 +367,9 @@
+ ? &next_long_name
+ : &next_long_link);
+
++ assign_string (¤t_file_name, header->header.name);
++ print_header();
++
+ set_next_block_after (header);
+ if (*longp)
+ free (*longp);
+@@ -614,7 +617,7 @@
+ char *name;
+
+ if (block_number_option)
+- fprintf (stdlis, _("block %10ld: "), current_block_ordinal ());
++ fprintf (stdrec, _("block %10ld: "), current_block_ordinal ());
+
+ if (verbose_option <= 1)
+ {
+@@ -624,11 +627,11 @@
+
+ if (quoted_name)
+ {
+- fprintf (stdlis, "%s\n", quoted_name);
++ fprintf (stdrec, "%s\n", quoted_name);
+ free (quoted_name);
+ }
+ else
+- fprintf (stdlis, "%s\n", current_file_name);
++ fprintf (stdrec, "%s\n", current_file_name);
+ }
+ else
+ {
+@@ -650,8 +653,12 @@
+ break;
+
+ case GNUTYPE_LONGNAME:
++ modes[0] = 'L';
++ break;
++
+ case GNUTYPE_LONGLINK:
+- ERROR ((0, 0, _("Visible longname error")));
++ /*ERROR ((0, 0, _("Visible longname error")));*/
++ modes[0] = 'K';
+ break;
+
+ case GNUTYPE_SPARSE:
+@@ -743,22 +750,22 @@
+ ugswidth = pad;
+
+ #if USE_OLD_CTIME
+- fprintf (stdlis, "%s %s/%s %*s%s %s %s",
++ fprintf (stdrec, "%s %s/%s %*s%s %s %s",
+ modes, user, group, ugswidth - pad, "",
+ size, timestamp + 4, timestamp + 20);
+ #else
+- fprintf (stdlis, "%s %s/%s %*s%s %s",
++ fprintf (stdrec, "%s %s/%s %*s%s %s",
+ modes, user, group, ugswidth - pad, "", size, timestamp);
+ #endif
+
+ name = quote_copy_string (current_file_name);
+ if (name)
+ {
+- fprintf (stdlis, " %s", name);
++ fprintf (stdrec, " %s", name);
+ free (name);
+ }
+ else
+- fprintf (stdlis, " %s", current_file_name);
++ fprintf (stdrec, " %s", current_file_name);
+
+ switch (current_header->header.typeflag)
+ {
+@@ -766,26 +773,26 @@
+ name = quote_copy_string (current_link_name);
+ if (name)
+ {
+- fprintf (stdlis, " -> %s\n", name);
++ fprintf (stdrec, " -> %s\n", name);
+ free (name);
+ }
+ else
+- fprintf (stdlis, " -> %s\n", current_link_name);
++ fprintf (stdrec, " -> %s\n", current_link_name);
+ break;
+
+ case LNKTYPE:
+ name = quote_copy_string (current_link_name);
+ if (name)
+ {
+- fprintf (stdlis, _(" link to %s\n"), name);
++ fprintf (stdrec, _(" link to %s\n"), name);
+ free (name);
+ }
+ else
+- fprintf (stdlis, _(" link to %s\n"), current_link_name);
++ fprintf (stdrec, _(" link to %s\n"), current_link_name);
+ break;
+
+ default:
+- fprintf (stdlis, _(" unknown file type `%c'\n"),
++ fprintf (stdrec, _(" unknown file type `%c'\n"),
+ current_header->header.typeflag);
+ break;
+
+@@ -798,24 +805,24 @@
+ case FIFOTYPE:
+ case CONTTYPE:
+ case GNUTYPE_DUMPDIR:
+- putc ('\n', stdlis);
++ putc ('\n', stdrec);
+ break;
+
+ case GNUTYPE_VOLHDR:
+- fprintf (stdlis, _("--Volume Header--\n"));
++ fprintf (stdrec, _("--Volume Header--\n"));
+ break;
+
+ case GNUTYPE_MULTIVOL:
+- fprintf (stdlis, _("--Continued at byte %ld--\n"),
++ fprintf (stdrec, _("--Continued at byte %ld--\n"),
+ from_oct (1 + 12, current_header->oldgnu_header.offset));
+ break;
+
+ case GNUTYPE_NAMES:
+- fprintf (stdlis, _("--Mangled file names--\n"));
++ fprintf (stdrec, _("--Mangled file names--\n"));
+ break;
+ }
+ }
+- fflush (stdlis);
++ fflush (stdrec);
+ }
+
+ /*--------------------------------------------------------------.
+@@ -836,16 +843,16 @@
+ decode_mode ((unsigned) mode, modes + 1);
+
+ if (block_number_option)
+- fprintf (stdlis, _("block %10ld: "), current_block_ordinal ());
++ fprintf (stdrec, _("block %10ld: "), current_block_ordinal ());
+ name = quote_copy_string (pathname);
+ if (name)
+ {
+- fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
++ fprintf (stdrec, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
+ _("Creating directory:"), length, name);
+ free (name);
+ }
+ else
+- fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
++ fprintf (stdrec, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
+ _("Creating directory:"), length, pathname);
+ }
+ }
+diff -ru tar-1.12/src/names.c tar-1.12.1/src/names.c
+--- tar-1.12/src/names.c Tue Apr 22 07:35:50 1997
++++ tar-1.12.1/src/names.c Fri Jul 3 12:46:24 1998
+@@ -332,6 +332,14 @@
+ FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
+ name_buffer));
+ chdir_flag = 0;
++ if ( record_file_name )
++ {
++ char *d = malloc(PATH_MAX);
++ if( d && getcwd(d,PATH_MAX) )
++ fprintf(stdrec,
++ "loc current directory is %s\n",
++ d);
++ }
+ }
+ else if (change_dirs && strcmp (name_buffer, "-C") == 0)
+ chdir_flag = 1;
+diff -ru tar-1.12/src/tar.c tar-1.12.1/src/tar.c
+--- tar-1.12/src/tar.c Fri Apr 25 22:09:49 1997
++++ tar-1.12.1/src/tar.c Tue Jul 28 15:44:57 1998
+@@ -163,6 +163,7 @@
+ #define SUFFIX_OPTION 15
+ #define USE_COMPRESS_PROGRAM_OPTION 16
+ #define VOLNO_FILE_OPTION 17
++#define OPTION_RECORD_FILE 18
+
+ /* Some cleanup is being made in GNU tar long options. Using old names is
+ allowed for a while, but will also send a warning to stderr. Take old
+@@ -251,6 +252,7 @@
+ {"read-full-records", no_argument, NULL, 'B'},
+ /* FIXME: --partial-blocks might be a synonym for --read-full-records? */
+ {"record-number", no_argument, NULL, OBSOLETE_BLOCK_NUMBER},
++ {"record-file", required_argument, NULL, OPTION_RECORD_FILE},
+ {"record-size", required_argument, NULL, RECORD_SIZE_OPTION},
+ {"remove-files", no_argument, &remove_files_option, 1},
+ {"rsh-command", required_argument, NULL, RSH_COMMAND_OPTION},
+@@ -410,6 +412,7 @@
+ --checkpoint print directory names while reading the archive\n\
+ --totals print total bytes written while creating archive\n\
+ -R, --block-number show block number within archive with each message\n\
++ --record-file print the record information to file, enable -R\n\
+ -w, --interactive ask for confirmation for every action\n\
+ --confirmation same as -w\n"),
+ stdout);
+@@ -754,6 +757,10 @@
+
+ block_number_option = 1;
+ break;
++
++ case OPTION_RECORD_FILE:
++ record_file_name = optarg ;
++ break;
+
+ case 's':
+ /* Names to extr are sorted. */
--- /dev/null
+diff -ru tar-1.13/src/buffer.c tar-1.13.1/src/buffer.c
+--- tar-1.13/src/buffer.c Mon Jul 5 08:47:59 1999
++++ tar-1.13.1/src/buffer.c Sun Aug 6 23:37:01 2000
+@@ -68,6 +68,7 @@
+ /* Where we write list messages (not errors, not interactions) to. Stdout
+ unless we're writing a pipe, in which case stderr. */
+ FILE *stdlis;
++FILE *stdrec;
+
+ static void backspace_output PARAMS ((void));
+ static int new_volume PARAMS ((enum access_mode));
+@@ -83,6 +84,9 @@
+ /* PID of child program, if compress_option or remote archive access. */
+ static pid_t child_pid;
+
++/* Record number of the start of this block of records */
++long baserec = 0 ;
++
+ /* Error recovery stuff */
+ static int read_error_count;
+
+@@ -144,9 +148,11 @@
+
+ #endif /* DEBUG FORK */
+
++time_t start_time ;
+ void
+ init_total_written (void)
+ {
++ start_time = time(0);
+ clear_tarlong (total_written);
+ clear_tarlong (bytes_written);
+ }
+@@ -154,8 +160,12 @@
+ void
+ print_total_written (void)
+ {
++ time_t end_time = time(0);
+ fprintf (stderr, _("Total bytes written: "));
+ print_tarlong (total_written, stderr);
++ fprintf (stderr, _(" ("));
++ print_tarlong ((total_written/(end_time-start_time))>>10, stderr);
++ fprintf (stderr,"KB per second)");
+ fprintf (stderr, "\n");
+ }
+
+@@ -680,8 +690,48 @@
+ open_archive (enum access_mode access)
+ {
+ int backed_up_flag = 0;
++ time_t start_time = time(0) ;
+
+- stdlis = to_stdout_option ? stderr : stdout;
++ stdrec = stdlis = to_stdout_option ? stderr : stdout;
++
++ if ( record_file_name != NULL )
++ {
++#define INSERT_TIMESTAMP
++#ifdef INSERT_TIMESTAMP
++ /*
++ * A record-file name with '%T' will be expanded with a decimal
++ * value for the timestamp of the archive. This is the time value
++ * stored in the label record.
++ * If you are using only one computer, this should be a unique number.
++ * You are able to create different rec-files for all your archives,
++ * as well as finding the index of your archive in a reliable way.
++ *
++ * Another way would be to let us set the timestamp by another option.
++ * tar --timestamp <ts-number> ...
++ */
++ char rfn[256];
++ if ( access == ACCESS_READ ) {
++ char*p= record_file_name ;
++ int i = 0 ;
++ int n;
++ while ( p[0] != '\0' ) {
++ if ( p[0] == '%' && p[1] == 'T' ) {
++ /* i += */ sprintf(rfn+i,"%d",start_time);
++ i = strlen(rfn) ;
++ p += 2 ;
++ } else { rfn[i++] = *p++ ; }
++ }
++ rfn[i] = '\0' ;
++ } else strcpy(rfn,record_file_name);
++#else
++ char*rfn=record_file_name;
++#endif
++ if ( ( stdrec = fopen(rfn,"w")) == NULL )
++ {
++ fprintf(stdlis,"Cannot open %s.\n",record_file_name);
++ exit(1);
++ }
++ }
+
+ if (record_size == 0)
+ FATAL_ERROR ((0, 0, _("Invalid value for record_size")));
+@@ -841,6 +891,46 @@
+ setmode (archive, O_BINARY);
+ #endif
+
++#if defined(MTIOCGET)
++ /* Prints the file number of the archive */
++ if ( block_number_option )
++ {
++ struct mtget get ;
++ int i ;
++ i = ioctl(archive,MTIOCGET,&get);
++ if (( i == 0 ) && ( get.mt_fileno >= 0 ))
++ {
++ fprintf(stdrec,
++ "loc number of the file is %d \n",
++ get.mt_fileno );
++ }
++ }
++#endif
++
++#if defined(MTIOCPOS)
++ /* Prints the tape block number on every Linux SCSI-device */
++ if ( block_number_option )
++ {
++ struct mtpos pos ;
++ int i ;
++ i = ioctl(archive,MTIOCPOS,&pos);
++ if ( i == 0 )
++ {
++ fprintf(stdrec,
++ "loc number of the first block is %d\n",
++ pos.mt_blkno );
++ }
++ }
++#endif
++
++ /* Prints the size of the blocks */
++ if ( block_number_option && blocking_factor != 20 )
++ {
++ fprintf(stdrec,
++ "loc block length is %d bytes = %d * 512 bytes\n",
++ blocking_factor*512,blocking_factor);
++ }
++
+ switch (access)
+ {
+ case ACCESS_READ:
+@@ -874,7 +964,7 @@
+ assign_string (¤t_file_name, record_start->header.name);
+
+ record_start->header.typeflag = GNUTYPE_VOLHDR;
+- TIME_TO_OCT (time (0), record_start->header.mtime);
++ TIME_TO_OCT (start_time, record_start->header.mtime);
+ finish_header (record_start);
+ #if 0
+ current_block++;
+diff -ru tar-1.13/src/common.h tar-1.13.1/src/common.h
+--- tar-1.13/src/common.h Wed Jul 7 08:07:30 1999
++++ tar-1.13.1/src/common.h Mon Feb 21 23:30:56 2000
+@@ -311,6 +311,12 @@
+
+ /* Initial size of the sparsearray. */
+ GLOBAL int sp_array_size;
++
++/* Time of writing. */
++GLOBAL time_t start_time;
++
++/* File to write record information to. */
++GLOBAL char *record_file_name;
+ \f
+ /* Declarations for each module. */
+
+@@ -327,7 +333,9 @@
+
+ /* Module buffer.c. */
+
++extern long baserec;
+ extern FILE *stdlis;
++extern FILE *stdrec;
+ extern char *save_name;
+ extern off_t save_sizeleft;
+ extern off_t save_totsize;
+diff -ru tar-1.13/src/create.c tar-1.13.1/src/create.c
+--- tar-1.13/src/create.c Wed Jul 7 07:27:04 1999
++++ tar-1.13.1/src/create.c Sun Aug 6 22:29:50 2000
+@@ -435,11 +435,9 @@
+
+ uintmax_to_oct ((uintmax_t) sum, header->header.chksum, 7);
+
+- set_next_block_after (header);
+-
+- if (verbose_option
+- && header->header.typeflag != GNUTYPE_LONGLINK
+- && header->header.typeflag != GNUTYPE_LONGNAME)
++ if (verbose_option)
++ /* && header->header.typeflag != GNUTYPE_LONGLINK */
++ /* && header->header.typeflag != GNUTYPE_LONGNAME */
+ {
+ /* These globals are parameters to print_header, sigh. */
+
+@@ -448,6 +446,9 @@
+ current_format = archive_format;
+ print_header ();
+ }
++
++ set_next_block_after (header);
++
+ }
+ \f
+ /* Sparse file processing. */
+diff -ru tar-1.13/src/extract.c tar-1.13.1/src/extract.c
+--- tar-1.13/src/extract.c Fri Jul 2 23:24:36 1999
++++ tar-1.13.1/src/extract.c Mon Feb 21 21:32:07 2000
+@@ -962,6 +962,7 @@
+ case GNUTYPE_LONGNAME:
+ case GNUTYPE_LONGLINK:
+ ERROR ((0, 0, _("Visible long name error")));
++ print_header();
+ skip_file (current_stat.st_size);
+ if (backup_option)
+ undo_last_backup ();
+diff -ru tar-1.13/src/list.c tar-1.13.1/src/list.c
+--- tar-1.13/src/list.c Wed Jul 7 07:46:52 1999
++++ tar-1.13.1/src/list.c Sun Aug 6 22:25:28 2000
+@@ -124,7 +124,7 @@
+ if (block_number_option)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+- fprintf (stdlis, _("block %s: ** Block of NULs **\n"),
++ fprintf (stdrec, _("block %s: ** Block of NULs **\n"),
+ STRINGIFY_BIGINT (current_block_ordinal (), buf));
+ }
+
+@@ -138,7 +138,7 @@
+ if (block_number_option)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+- fprintf (stdlis, _("block %s: ** End of File **\n"),
++ fprintf (stdrec, _("block %s: ** End of File **\n"),
+ STRINGIFY_BIGINT (current_block_ordinal (), buf));
+ }
+ break;
+@@ -217,7 +217,7 @@
+ if (written > size)
+ written = size;
+ errno = 0; /* FIXME: errno should be read-only */
+- check = fwrite (data_block->buffer, sizeof (char), written, stdlis);
++ check = fwrite (data_block->buffer, sizeof (char), written, stdrec);
+ set_next_block_after ((union block *)
+ (data_block->buffer + written - 1));
+ if (check != written)
+@@ -231,8 +231,8 @@
+ }
+ if (multi_volume_option)
+ assign_string (&save_name, NULL);
+- fputc ('\n', stdlis);
+- fflush (stdlis);
++ fputc ('\n', stdrec);
++ fflush (stdrec);
+ return;
+
+ }
+@@ -381,6 +381,8 @@
+ longp = ((header->header.typeflag == GNUTYPE_LONGNAME)
+ ? &next_long_name
+ : &next_long_link);
++ assign_string (¤t_file_name, header->header.name);
++ print_header();
+
+ set_next_block_after (header);
+ if (*longp)
+@@ -763,10 +765,18 @@
+ int pad;
+ char *name;
+
++ extern union block *record_start;
++ extern union block *current_block;
++ if (block_number_option)
++ fprintf (stdrec, _("rec %10ld: "), baserec + (current_block - record_start));
++#if 0
++ annofile (stdrec, (char *) NULL);
++#endif
++
+ if (block_number_option)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+- fprintf (stdlis, _("block %s: "),
++ fprintf (stdrec, _("block %s: "),
+ STRINGIFY_BIGINT (current_block_ordinal (), buf));
+ }
+
+@@ -778,11 +788,11 @@
+
+ if (quoted_name)
+ {
+- fprintf (stdlis, "%s\n", quoted_name);
++ fprintf (stdrec, "%s\n", quoted_name);
+ free (quoted_name);
+ }
+ else
+- fprintf (stdlis, "%s\n", current_file_name);
++ fprintf (stdrec, "%s\n", current_file_name);
+ }
+ else
+ {
+@@ -792,6 +802,11 @@
+ switch (current_header->header.typeflag)
+ {
+ case GNUTYPE_VOLHDR:
++ /* dirty bug fix to display the header processing
++ * tar cvvf /dev/null --label 'hello world' blah...
++ * J"org Weule weule@cs.uni-duesseldorf.de
++ */
++ current_stat.st_mtime = time_from_oct(current_block->header.mtime,1+12);
+ modes[0] = 'V';
+ break;
+
+@@ -804,8 +819,12 @@
+ break;
+
+ case GNUTYPE_LONGNAME:
++ modes[0] = 'L';
++ break;
++
+ case GNUTYPE_LONGLINK:
+- ERROR ((0, 0, _("Visible longname error")));
++ /* ERROR ((0, 0, _("Visible longname error"))); */
++ modes[0] = 'K' ;
+ break;
+
+ case GNUTYPE_SPARSE:
+@@ -898,22 +917,22 @@
+ ugswidth = pad;
+
+ #if USE_OLD_CTIME
+- fprintf (stdlis, "%s %s/%s %*s%s %s %s",
++ fprintf (stdrec, "%s %s/%s %*s%s %s %s",
+ modes, user, group, ugswidth - pad, "",
+ size, timestamp + 4, timestamp + 20);
+ #else
+- fprintf (stdlis, "%s %s/%s %*s%s %s",
++ fprintf (stdrec, "%s %s/%s %*s%s %s",
+ modes, user, group, ugswidth - pad, "", size, timestamp);
+ #endif
+
+ name = quote_copy_string (current_file_name);
+ if (name)
+ {
+- fprintf (stdlis, " %s", name);
++ fprintf (stdrec, " %s", name);
+ free (name);
+ }
+ else
+- fprintf (stdlis, " %s", current_file_name);
++ fprintf (stdrec, " %s", current_file_name);
+
+ switch (current_header->header.typeflag)
+ {
+@@ -921,26 +940,26 @@
+ name = quote_copy_string (current_link_name);
+ if (name)
+ {
+- fprintf (stdlis, " -> %s\n", name);
++ fprintf (stdrec, " -> %s\n", name);
+ free (name);
+ }
+ else
+- fprintf (stdlis, " -> %s\n", current_link_name);
++ fprintf (stdrec, " -> %s\n", current_link_name);
+ break;
+
+ case LNKTYPE:
+ name = quote_copy_string (current_link_name);
+ if (name)
+ {
+- fprintf (stdlis, _(" link to %s\n"), name);
++ fprintf (stdrec, _(" link to %s\n"), name);
+ free (name);
+ }
+ else
+- fprintf (stdlis, _(" link to %s\n"), current_link_name);
++ fprintf (stdrec, _(" link to %s\n"), current_link_name);
+ break;
+
+ default:
+- fprintf (stdlis, _(" unknown file type `%c'\n"),
++ fprintf (stdrec, _(" unknown file type `%c'\n"),
+ current_header->header.typeflag);
+ break;
+
+@@ -953,11 +972,11 @@
+ case FIFOTYPE:
+ case CONTTYPE:
+ case GNUTYPE_DUMPDIR:
+- putc ('\n', stdlis);
++ putc ('\n', stdrec);
+ break;
+
+ case GNUTYPE_VOLHDR:
+- fprintf (stdlis, _("--Volume Header--\n"));
++ fprintf (stdrec, _("--Volume Header--\n"));
+ break;
+
+ case GNUTYPE_MULTIVOL:
+@@ -965,15 +984,15 @@
+ STRINGIFY_BIGINT
+ (UINTMAX_FROM_OCT (current_header->oldgnu_header.offset),
+ uintbuf));
+- fprintf (stdlis, _("--Continued at byte %s--\n"), size);
++ fprintf (stdrec, _("--Continued at byte %s--\n"), size);
+ break;
+
+ case GNUTYPE_NAMES:
+- fprintf (stdlis, _("--Mangled file names--\n"));
++ fprintf (stdrec, _("--Mangled file names--\n"));
+ break;
+ }
+ }
+- fflush (stdlis);
++ fflush (stdrec);
+ }
+
+ /*--------------------------------------------------------------.
+@@ -996,7 +1015,7 @@
+ if (block_number_option)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+- fprintf (stdlis, _("block %s: "),
++ fprintf (stdrec, _("block %s: "),
+ STRINGIFY_BIGINT (current_block_ordinal (), buf));
+ }
+ name = quote_copy_string (pathname);
+diff -ru tar-1.13/src/names.c tar-1.13.1/src/names.c
+--- tar-1.13/src/names.c Wed Jul 7 07:46:51 1999
++++ tar-1.13.1/src/names.c Sun Aug 6 22:20:43 2000
+@@ -375,6 +375,14 @@
+ FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
+ name_buffer));
+ chdir_flag = 0;
++ if ( record_file_name )
++ {
++ char *d = malloc(PATH_MAX);
++ if( d && getcwd(d,PATH_MAX) )
++ fprintf(stdrec,
++ "loc current directory is %s\n",
++ d);
++ }
+ }
+ else if (change_dirs && strcmp (name_buffer, "-C") == 0)
+ chdir_flag = 1;
+diff -ru tar-1.13/src/tar.c tar-1.13.1/src/tar.c
+--- tar-1.13/src/tar.c Wed Jul 7 07:49:50 1999
++++ tar-1.13.1/src/tar.c Tue Feb 22 00:27:07 2000
+@@ -132,6 +132,7 @@
+ SUFFIX_OPTION,
+ USE_COMPRESS_PROGRAM_OPTION,
+ VOLNO_FILE_OPTION,
++ RECORD_FILE_OPTION,
+
+ /* Some cleanup is being made in GNU tar long options. Using old names is
+ allowed for a while, but will also send a warning to stderr. Take old
+@@ -220,6 +221,7 @@
+ /* FIXME: --partial-blocks might be a synonym for --read-full-records? */
+ {"record-number", no_argument, NULL, OBSOLETE_BLOCK_NUMBER},
+ {"record-size", required_argument, NULL, RECORD_SIZE_OPTION},
++ {"record-file", required_argument, NULL, RECORD_FILE_OPTION},
+ {"remove-files", no_argument, &remove_files_option, 1},
+ {"rsh-command", required_argument, NULL, RSH_COMMAND_OPTION},
+ {"same-order", no_argument, NULL, 's'},
+@@ -378,6 +380,7 @@
+ --checkpoint print directory names while reading the archive\n\
+ --totals print total bytes written while creating archive\n\
+ -R, --block-number show block number within archive with each message\n\
++ --record-file print the record information to file, enable -R\n\
+ -w, --interactive ask for confirmation for every action\n\
+ --confirmation same as -w\n"),
+ stdout);
+@@ -904,6 +907,11 @@
+ volno_file_option = optarg;
+ break;
+
++ case RECORD_FILE_OPTION:
++ record_file_name = optarg ;
++ block_number_option++; /* Print block #s for debug */
++ break;
++
+ case USE_COMPRESS_PROGRAM_OPTION:
+ set_use_compress_program_option (optarg);
+ break;
+@@ -1155,14 +1163,52 @@
+ break;
+
+ case CREATE_SUBCOMMAND:
++
++/*
++ * Comment the next line out if you have problems. Joerg Weule
++ */
++#define PRINT_TROUPUT
++#ifdef PRINT_TROUPUT
++ start_time = time(0);
+ if (totals_option)
+- init_total_written ();
++ init_total_written ();
++ create_archive ();
++ if (totals_option) {
++ time_t end_time = time(0);
++ double sec = end_time - start_time ;
++ /* double t = ((double)total_written) * BLOCKSIZE ; */
++ print_total_written ();
++ /*
++ fprintf (stderr, _("Total bytes written: %.0f"),t);
++ if ( t >= 1e9 ) fprintf(stderr, _(" (%3.1f Gb)"),t/1e9 ); else
++ if ( t >= 1e6 ) fprintf(stderr, _(" (%3.1f Mb)"),t/1e6 ); else
++ if ( t >= 1024 ) fprintf(stderr, _(" (%3.1f Kb)"),t/1024 );
++ fprintf(stderr,"\n");
++ if ( sec > 0.1 ){
++ long s, m, h = sec ;
++ m = h ;
++ h /= 3600 ;
++ m -= h * 3600 ;
++ s = m ;
++ m /= 60 ;
++ s -= m / 60 ;
++ fprintf (stderr, _("Elapsed time: %02d:%02d:%02d, %g sec\n"), h,m,s,sec);
++ if ( !flag_multivol)
++ fprintf (stderr, _("Throughput per second: %.0fKb/sec\n"),
++ t/sec/1024);
++ }
++ */
++ }
++#else
++ if (totals_option)
++ init_total_written ();
+
+ create_archive ();
+ name_close ();
+
+ if (totals_option)
+- print_total_written ();
++ print_total_written ();
++#endif
+ break;
+
+ case EXTRACT_SUBCOMMAND:
--- /dev/null
+
+/*
+ * This file is part of dds2tar.
+ * Copyright by J"org Weule
+ *
+ * Copyright: GPL
+ */
+
+/*
+ * If you compile this file with -DTEST, you will get a test program:
+ *
+ * cc dds_fio.c -DTEST -o dds_fio && dds_fio
+ *
+ * The test shows the use of ccopen(...) to pipe stdout through /bin/grep.
+ *
+ * The interface should be useful in many cases.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mtio.h>
+#include <string.h>
+#include <unistd.h> /* pipe() ... */
+#include <sys/types.h> /* size_t, open() */
+#include <sys/wait.h> /* wait() */
+#include <sys/stat.h> /* open() */
+#include <fcntl.h> /* open() */
+
+#include "zf-cre-open.h"
+
+#define streq(a,b) (!strcmp((a),(b)))
+
+FILE *
+zfopen(
+ char const *const name,
+ int const compressed,
+ char const *const open_mode
+)
+{
+
+ FILE *fp;
+ char *b;
+
+ b = malloc(1024);
+ if (b == NULL)
+ exit(20);
+
+ if (compressed == T_MODE) {
+ if ((name != NULL) && (strcmp(name, "-"))) {
+ fp = fopen(name, open_mode);
+ if (fp == NULL) {
+ perror("dds2tar");
+ exit(21);
+ }
+ } else if (streq(open_mode, "w")) {
+ fp = stdout;
+ } else {
+ fp = stdin;
+ }
+ return fp;
+ }
+ if (streq(open_mode, "w")) {
+ strcpy(b, "gzip ");
+ if ((name != NULL) && (strcmp(name, "-"))) {
+ strcat(b, " > ");
+ strcat(b, name);
+ }
+ } else if (streq(open_mode, "r")) {
+ strcpy(b, "gunzip --force --decompress --stdout ");
+ if ((name != NULL) && (strcmp(name, "-"))) {
+ strcat(b, name);
+ }
+ }
+ fp = popen(b, open_mode);
+ if (fp == NULL) {
+ perror("dds2tar");
+ exit(22);
+ }
+ free(b);
+ return fp;
+}
+
+
+int
+cclose(int const fd)
+{
+ int status = 0;
+
+ close(fd);
+ wait(&status);
+ return status;
+}
+
+int
+reopen(
+ int const stdfd,
+ char const *const output_file,
+ int const mode,
+ int const flags
+)
+{
+ int fd;
+
+ if (!strcmp(output_file, "-")) {
+ /* use stdout */
+ fd = 1;
+ } else {
+ /* open file */
+ if ((fd = open(output_file, mode, flags)) == -1) {
+ perror("dds2tar");
+ exit(23);
+ }
+ /* don't know why this happens. Any idea? */
+ if (fd == 0) { /* normally 0 is stdin!! */
+ perror("dds2tar");
+ exit(24);
+ }
+ }
+ if (0 <= stdfd) {
+ dup2(fd, stdfd);
+ close(fd);
+ fd = stdfd;
+ }
+ return fd;
+}
+
+/*
+ * creopen opens a pipe to a child process with the file number 'stdfd'
+ * on file number 'stdfd_child' of the child.
+ * The files are close as needed (see dup2(2)).
+ */
+
+int
+creopen(
+ int const stdfd_parent, /* stdfd should not be == 3 */
+ int const stdfd_child, /* stdfd_child must be 1 or 2 */
+ char const *const filename,
+ char const *const *argv
+)
+{
+ int fd;
+ int pid;
+ int pipefd[2];
+ int pipe_parent;
+
+ if ((stdfd_child & 0xfffffffe) != 0 || stdfd_child == stdfd_parent) {
+ fprintf(stderr, "creopen not useful with that parameters\n");
+ exit(25);
+ }
+ pipe_parent = stdfd_child ^ 1;
+ if (pipe(pipefd) < 0) { /* create pipe with two fd's */
+ perror("dds2tar");
+ exit(26);
+ }
+ if ((pid = fork()) == 0) { /* we are the child process */
+ /* reconnect pipe to child */
+ dup2(pipefd[stdfd_child], stdfd_child);
+ close(pipefd[0]); /* close input of pipe */
+ close(pipefd[1]); /* close output of pipe */
+ /* the prototype of execv is wrong */
+ execv(filename, (char *const *) argv);
+ perror("dds2tar");
+ exit(27);
+ }
+ if (pid <= 0) {
+ perror("dds2tar");
+ exit(28);
+ }
+ /*
+ * We are the parent process.
+ */
+ close(stdfd_child);
+ fd = pipefd[pipe_parent];
+ if ((0 <= stdfd_parent) && (stdfd_parent <= 1)) {
+ dup2(fd, stdfd_parent);
+ close(fd);
+ fd = stdfd_parent;
+ close(pipefd[0]);
+ close(pipefd[1]);
+ }
+ return fd;
+}
+
+#ifdef TEST
+
+static char *a[] =
+{"grep", "allo", NULL};
+
+main(int argc, char **argv, char **envp)
+{
+
+ int status;
+ int pid;
+ int fd;
+
+ if (!strcmp(argv[1], "-p")) {
+ } else {
+ if (!strcmp(argv[1], "-o"))
+ reopen(1, argv[2], O_RDONLY, 0);
+ else
+ creopen(1, 0, "/usr/bin/grep", a);
+ write(1, "Hallo World -1- \n", 17);
+ write(1, "Hi World -2- \n", 17);
+ write(1, "Hallo World -3- \n", 17);
+ write(1, "Morgen Welt -4- \n", 17);
+ write(1, "Hallo World -5- \n", 17);
+ printf("Hallo World =1= \n");
+ printf("Hi World =2= \n");
+ printf("Hallo World =3= \n");
+ printf("Morgen Welt =4= \n");
+ printf("Hallo World =5= \n");
+ fflush(stdout);
+ if (!strcmp(argv[1], "-o")) {
+ close(1);
+ } else {
+ cclose(1);
+ }
+ }
+}
+
+#endif
--- /dev/null
+
+/*
+ * This file is part of dds2tar.
+ * Copyright by J"org Weule
+ *
+ * Copyright: GPL
+ */
+
+#define C_MODE 1 /* compressed */
+#define T_MODE 0 /* transparent */
+
+/*
+ * Use popen and gzip to open a file with transparent compression.
+ * The mode may be "r" or "w".
+ */
+extern FILE *zfopen(
+ char const *, /* pathname */
+ int const, /* compression, e.g. 0 or 1 */
+ char const *const /* open mode, e.g. "r" or "w" */
+);
+
+/*
+ * Open a pipe to a child process on a given file number, e.g. 1.
+ *
+ * Example of a pipe to tar -t:
+ * static char * av[] = {"/bin/tar","-t",NULL};
+ * creopen(1,0,"/bin/tar",av,NULL);
+ */
+extern int creopen(
+ int const, /* file number of the parent */
+ int const, /* file number of the child */
+ char const *const, /* name of the program */
+ char const *const * /* argv of the program */
+
+);
+extern int cclose(int const);
+
+/*
+ * Open a file on a given file number, e.g. 1.
+ */
+extern int reopen(
+ int const, /* file number */
+ char const *const, /* name of the file */
+ int const, /* mode of the open */
+ int const /* file mode */
+);