mirror of
https://github.com/brouhaha/tapeutils.git
synced 2026-01-11 23:53:18 +00:00
Import version 0.4 from http://www.brouhaha.com/~eric/software/tapeutils/
This commit is contained in:
commit
86e5f36943
339
COPYING
Normal file
339
COPYING
Normal file
@ -0,0 +1,339 @@
|
||||
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.
|
||||
|
||||
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.)
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
67
Makefile
Normal file
67
Makefile
Normal file
@ -0,0 +1,67 @@
|
||||
# Makefile for tapeutils
|
||||
# Copyright 1998, 1999, 2000 Eric Smith
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as published
|
||||
# by the Free Software Foundation. Note that permission is not granted
|
||||
# to redistribute this program under the terms of any later version of the
|
||||
# General Public License.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# options
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
CFLAGS = -O2
|
||||
LDFLAGS =
|
||||
|
||||
# CFLAGS = -g
|
||||
# LDFLAGS = -g
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# You shouldn't have to change anything below this point, but if you do please
|
||||
# let me know why so I can improve this Makefile.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
PACKAGE = tapeutils
|
||||
VERSION = 0.4
|
||||
DSTNAME = $(PACKAGE)-$(VERSION)
|
||||
|
||||
PROGRAMS = tapecopy tapedump
|
||||
|
||||
HEADERS = tapeio.h
|
||||
SOURCES = tapeio.c tapecopy.c tapedump.c
|
||||
MISC = COPYING
|
||||
|
||||
DISTFILES = $(MISC) Makefile $(HEADERS) $(SOURCES)
|
||||
|
||||
all: $(PROGRAMS) $(MISC_TARGETS)
|
||||
|
||||
dist: $(DISTFILES)
|
||||
-rm -rf $(DSTNAME)
|
||||
mkdir $(DSTNAME)
|
||||
for f in $(DISTFILES); do ln $$f $(DSTNAME)/$$f; done
|
||||
tar --gzip -chf $(DSTNAME).tar.gz $(DSTNAME)
|
||||
-rm -rf $(DSTNAME)
|
||||
|
||||
clean:
|
||||
rm -f $(PROGRAMS) $(MISC_TARGETS) *.o
|
||||
|
||||
|
||||
tapecopy: tapecopy.o tapeio.o
|
||||
|
||||
tapedump: tapedump.o tapeio.o
|
||||
|
||||
|
||||
include $(SOURCES:.c=.d)
|
||||
|
||||
%.d: %.c
|
||||
$(CC) -M -MG $(CFLAGS) $< | sed -e 's@ /[^ ]*@@g' -e 's@^\(.*\)\.o:@\1.d \1.o:@' > $@
|
||||
177
tapecopy.c
Normal file
177
tapecopy.c
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
tapecopy
|
||||
|
||||
This program uses a modified version of John Wilson's tapeio library to
|
||||
copy tapes between any of the following:
|
||||
|
||||
local tape drives - pathname starting with /dev/
|
||||
remote tape drives (rmt) - pathname containing a colon
|
||||
Wilson-format tape image files - any other pathname
|
||||
|
||||
Copyright 1999, 2000 Eric Smith
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as published
|
||||
by the Free Software Foundation. Note that permission is not granted
|
||||
to redistribute this program under the terms of any other version of the
|
||||
General Public License.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "tapeio.h"
|
||||
#include "stdio.h"
|
||||
#include "stdarg.h"
|
||||
|
||||
#define MAX_REC_LEN 32768
|
||||
|
||||
char *progname;
|
||||
|
||||
char *buf;
|
||||
|
||||
void print_usage (FILE *f)
|
||||
{
|
||||
fprintf (f, "Usage: %s [-v] in out\n", progname);
|
||||
}
|
||||
|
||||
void fatal (int retval, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (fmt)
|
||||
{
|
||||
fprintf (stderr, "%s: ", progname);
|
||||
va_start (ap, fmt);
|
||||
vfprintf (stderr, fmt, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
if (retval == 1)
|
||||
print_usage (stderr);
|
||||
|
||||
exit (retval);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int file = 0;
|
||||
unsigned long filebytes = 0;
|
||||
unsigned long tapebytes = 0;
|
||||
int prevlen = -2;
|
||||
int lencount = 0;
|
||||
int firstrec = 0;
|
||||
int len;
|
||||
int verbose = 0;
|
||||
char *srcfn = NULL;
|
||||
char *destfn = NULL;
|
||||
tape_handle src = NULL;
|
||||
tape_handle dest = NULL;
|
||||
|
||||
progname = argv [0];
|
||||
|
||||
while (++argv, --argc)
|
||||
{
|
||||
if ((argv [0][0] == '-') && (argv [0][1] != '\0'))
|
||||
{
|
||||
if (argv [0][1] == 'v')
|
||||
verbose++;
|
||||
else
|
||||
fatal (1, "unrecognized option '%s'\n", argv [0]);
|
||||
}
|
||||
else if (! srcfn)
|
||||
srcfn = argv [0];
|
||||
else if (! destfn)
|
||||
destfn = argv [0];
|
||||
else
|
||||
fatal (1, NULL);
|
||||
}
|
||||
|
||||
if (! srcfn)
|
||||
fatal (1, NULL);
|
||||
|
||||
buf = (char *) malloc (MAX_REC_LEN);
|
||||
if (! buf)
|
||||
fatal (2, "can't allocate buffer\n");
|
||||
|
||||
src = opentape (srcfn, 0, 0);
|
||||
if (! src)
|
||||
fatal (3, "can't open source tape\n");
|
||||
|
||||
if (destfn)
|
||||
{
|
||||
dest = opentape (destfn, 1, 1);
|
||||
if (! dest)
|
||||
fatal (4, "can't open dest tape\n");
|
||||
}
|
||||
else
|
||||
verbose++;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
len = getrec (src, buf, MAX_REC_LEN);
|
||||
if ((lencount != 0) && ((len == 0) || (len != prevlen)))
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
if (lencount == 1)
|
||||
printf ("1 record (%d)\n", firstrec);
|
||||
else
|
||||
printf ("%d records (%d..%d)\n", lencount, firstrec,
|
||||
firstrec+lencount-1);
|
||||
fflush (stdout);
|
||||
}
|
||||
filebytes += prevlen * lencount;
|
||||
firstrec += lencount;
|
||||
prevlen = -1;
|
||||
lencount = 0;
|
||||
}
|
||||
if (len != 0)
|
||||
{
|
||||
if (lencount == 0)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf ("file %d record length %d: ", file, len);
|
||||
fflush (stdout);
|
||||
}
|
||||
}
|
||||
if (destfn)
|
||||
putrec (dest, buf, len);
|
||||
lencount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
tapebytes += filebytes;
|
||||
if (verbose)
|
||||
{
|
||||
if (prevlen == 0)
|
||||
printf ("end of tape, %lu total bytes\n", tapebytes);
|
||||
else
|
||||
printf ("end of file %d, %lu bytes\n", file, filebytes);
|
||||
fflush (stdout);
|
||||
}
|
||||
if (destfn)
|
||||
tapemark (dest);
|
||||
if (prevlen == 0)
|
||||
break;
|
||||
file++;
|
||||
lencount = 0;
|
||||
firstrec = 0;
|
||||
filebytes = 0;
|
||||
}
|
||||
prevlen = len;
|
||||
}
|
||||
|
||||
closetape (src);
|
||||
if (destfn)
|
||||
closetape (dest);
|
||||
|
||||
return (0);
|
||||
}
|
||||
187
tapedump.c
Normal file
187
tapedump.c
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
tapedump
|
||||
|
||||
This program uses a modified version of John Wilson's tapeio library to
|
||||
copy tapes between any of the following:
|
||||
|
||||
local tape drives - pathname starting with /dev/
|
||||
remote tape drives (rmt) - pathname containing a colon
|
||||
Wilson-format tape image files - any other pathname
|
||||
|
||||
Copyright 1999, 2000 Eric Smith
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as published
|
||||
by the Free Software Foundation. Note that permission is not granted
|
||||
to redistribute this program under the terms of any other version of the
|
||||
General Public License.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "tapeio.h"
|
||||
#include "stdio.h"
|
||||
#include "stdarg.h"
|
||||
|
||||
#define MAX_REC_LEN 32768
|
||||
|
||||
char *progname;
|
||||
|
||||
void print_usage (FILE *f)
|
||||
{
|
||||
fprintf (f, "Usage: %s in\n", progname);
|
||||
}
|
||||
|
||||
void fatal (int retval, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (fmt)
|
||||
{
|
||||
fprintf (stderr, "%s: ", progname);
|
||||
va_start (ap, fmt);
|
||||
vfprintf (stderr, fmt, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
if (retval == 1)
|
||||
print_usage (stderr);
|
||||
|
||||
exit (retval);
|
||||
}
|
||||
|
||||
|
||||
#define BYTES_PER_LINE 16
|
||||
|
||||
void dump (FILE *f, char *buf, int len)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < len; i += BYTES_PER_LINE)
|
||||
{
|
||||
fprintf (f, " %04x: ", i);
|
||||
for (j = 0; j < BYTES_PER_LINE; j++)
|
||||
if ((i + j) < len)
|
||||
fprintf (f, "%02x ", 0xff & buf [i+j]);
|
||||
else
|
||||
fprintf (f, " ");
|
||||
for (j = 0; j < BYTES_PER_LINE; j++)
|
||||
if ((i + j) < len)
|
||||
{
|
||||
char c = buf [i+j] & 0x7f;
|
||||
if ((buf [i+j] >= ' ') && (buf [i+j] <= '~'))
|
||||
fprintf (f, "%c", buf [i+j]);
|
||||
else
|
||||
fprintf (f, ".");
|
||||
}
|
||||
else
|
||||
fprintf (f, " ");
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HP_2000_SUPPORT
|
||||
|
||||
#define MAX_FN_LEN 6
|
||||
|
||||
void dump_hp_2000_file_header (FILE *f, char *buf)
|
||||
{
|
||||
unsigned long uid;
|
||||
char uids [6];
|
||||
char filename [MAX_FN_LEN + 1];
|
||||
int i;
|
||||
uid = ((buf [0] & 0xff) << 8) | (buf [1] & 0xff);
|
||||
uids [0] = (uid / 1024) + '@';
|
||||
sprintf (& uids [1], "%03d", uid & 0x3ff);
|
||||
for (i = 0; i < MAX_FN_LEN; i++)
|
||||
filename [i] = buf [i+2] & 0x7f;
|
||||
filename [sizeof (filename) - 1] = '\0';
|
||||
fprintf (f, " id %s filename '%s'\n", uids, filename);
|
||||
}
|
||||
|
||||
#endif /* HP_2000_SUPPORT */
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int file = 0;
|
||||
int record = 0;
|
||||
unsigned long filebytes = 0;
|
||||
unsigned long tapebytes = 0;
|
||||
int len;
|
||||
char *srcfn = NULL;
|
||||
tape_handle src = NULL;
|
||||
char *buf;
|
||||
#ifdef HP_2000_SUPPORT
|
||||
int hp_2000_hibernate = 0;
|
||||
#endif /* HP_2000_SUPPORT */
|
||||
|
||||
progname = argv [0];
|
||||
|
||||
while (++argv, --argc)
|
||||
{
|
||||
if ((argv [0][0] == '-') && (argv [0][1] != '\0'))
|
||||
{
|
||||
#ifdef HP_2000_SUPPORT
|
||||
if (argv [0][1] == 'h')
|
||||
hp_2000_hibernate++;
|
||||
else
|
||||
#endif /* HP_2000_SUPPORT */
|
||||
fatal (1, "unrecognized option '%s'\n", argv [0]);
|
||||
}
|
||||
else if (! srcfn)
|
||||
srcfn = argv [0];
|
||||
else
|
||||
fatal (1, NULL);
|
||||
}
|
||||
|
||||
if (! srcfn)
|
||||
fatal (1, NULL);
|
||||
|
||||
buf = (char *) malloc (MAX_REC_LEN);
|
||||
if (! buf)
|
||||
fatal (2, "can't allocate buffer\n");
|
||||
|
||||
src = opentape (srcfn, 0, 0);
|
||||
if (! src)
|
||||
fatal (3, "can't open source tape\n");
|
||||
|
||||
for (;;)
|
||||
{
|
||||
len = getrec (src, buf, MAX_REC_LEN);
|
||||
if (len == 0)
|
||||
{
|
||||
printf ("total length of file %d = %d records, %d bytes\n",
|
||||
file, record, filebytes);
|
||||
tapebytes += filebytes;
|
||||
file++;
|
||||
record = 0;
|
||||
filebytes = 0;
|
||||
printf ("start of file %d\n", file);
|
||||
fflush (stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("file %d record %d: length %d\n", file, record, len);
|
||||
#ifdef HP_2000_SUPPORT
|
||||
if (hp_2000_hibernate && (file > 0) && (record == 0) && (len >= 24))
|
||||
dump_hp_2000_file_header (stdout, buf);
|
||||
#endif /* HP_2000_SUPPORT */
|
||||
dump (stdout, buf, len);
|
||||
fflush (stdout);
|
||||
filebytes += len;
|
||||
record++;
|
||||
}
|
||||
}
|
||||
|
||||
closetape (src);
|
||||
|
||||
return (0);
|
||||
}
|
||||
649
tapeio.c
Normal file
649
tapeio.c
Normal file
@ -0,0 +1,649 @@
|
||||
/*
|
||||
Routines to do magtape I/O to local tapes, remote tapes, and tape image
|
||||
files.
|
||||
|
||||
Copyright 1998, 1999 John Wilson and Eric Smith
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as published
|
||||
by the Free Software Foundation. Note that permission is not granted
|
||||
to redistribute this program under the terms of any other version of the
|
||||
General Public License.
|
||||
|
||||
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.
|
||||
|
||||
08/10/93 JMBW IBM mainframe TCP socket stuff (was using many files).
|
||||
07/08/94 JMBW Local magtape code.
|
||||
03/13/95 JMBW Converted to separate routines.
|
||||
07/19/98 JMBW Added support for "rmt" remote tape protocol.
|
||||
11/16/98 ELS Provide struct for per-instance variables.
|
||||
02/06/98 ELS Reorganization, and added skiprec and skipfile.
|
||||
*/
|
||||
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h> /* for lseek() SEEK_SET, SEEK_END under Linux */
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _AIX /* maybe this will be enough to make it compile on AIX */
|
||||
#include <sys/tape.h>
|
||||
#define MTWEOF STWEOF
|
||||
#define MTREW STREW
|
||||
#define MTFSR STFSR
|
||||
#define MTFSF STFSF
|
||||
#define MTBSR STRSR
|
||||
#define MTIOCTOP STIOCTOP
|
||||
/* not sure about these two (SCSI only): */
|
||||
#define MTSETBLK STSETBLK
|
||||
#define MTSETDENSITY STSETDENSITY
|
||||
#define mtop stop
|
||||
#else
|
||||
#include <sys/mtio.h>
|
||||
#endif
|
||||
|
||||
#include "tapeio.h"
|
||||
|
||||
|
||||
#define TT_UNK 0
|
||||
#define TT_TAPE 1 /* honest to god tape drive */
|
||||
#define TT_IMAGE 2 /* file containing image of a tape */
|
||||
#define TT_RMT 3 /* rmt tape server */
|
||||
|
||||
|
||||
struct mtape_t
|
||||
{
|
||||
int tape_type;
|
||||
int tapefd; /* tape drive, file, or socket file descriptor */
|
||||
int seek_ok;
|
||||
|
||||
unsigned long bpi; /* tape density (for tape length msg) */
|
||||
int waccess; /* NZ => tape opened for write access access */
|
||||
unsigned long count; /* count of frames written to tape */
|
||||
|
||||
char netbuf[80]; /* buffer for net commands and responses */
|
||||
};
|
||||
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
/* default tape drive device name */
|
||||
#define TAPE "/dev/nst0"
|
||||
/* default tape density */
|
||||
#define BPI 1600
|
||||
|
||||
|
||||
/* magtape commands */
|
||||
static struct mtop mt_weof={ MTWEOF, 1 }; /* operation, count */
|
||||
static struct mtop mt_rew={ MTREW, 1 };
|
||||
static struct mtop mt_fsr={ MTFSR, 1 };
|
||||
static struct mtop mt_fsf={ MTFSF, 1 };
|
||||
static struct mtop mt_bsr={ MTBSR, 1 };
|
||||
/* SCSI only: */
|
||||
static struct mtop mt_setblk={ MTSETBLK, 0 }; /* blockize = 0 (variable) */
|
||||
static struct mtop mt_setden={ MTSETDENSITY, 0x02 }; /* density = 1600 */
|
||||
|
||||
|
||||
#define FAIL(msg) do { fprintf (stderr, msg); goto fail; } while (0)
|
||||
|
||||
|
||||
/* do a write and check the return status, punt on error */
|
||||
static void dowrite (int handle, char *buf, int len)
|
||||
{
|
||||
if (write (handle, buf, len) != len)
|
||||
{
|
||||
perror ("?Error on write");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* do a read and keep trying until we get all bytes */
|
||||
static void doread (int handle, char *buf, int len)
|
||||
{
|
||||
int n;
|
||||
while(len)
|
||||
{
|
||||
if ((n = read (handle, buf, len)) < 0)
|
||||
{
|
||||
perror("?Error on read");
|
||||
exit (1);
|
||||
}
|
||||
if (n == 0)
|
||||
{
|
||||
fprintf (stderr, "?Unexpected end of file\n");
|
||||
exit (1);
|
||||
}
|
||||
buf += n;
|
||||
len -= n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* get response from "rmt" server */
|
||||
static int response (tape_handle mtape)
|
||||
{
|
||||
char c, rc;
|
||||
int n;
|
||||
|
||||
doread (mtape->tapefd, &rc, 1); /* get success/error code */
|
||||
if (rc != 'A' && rc != 'E')
|
||||
{ /* must be Acknowledge or Error */
|
||||
fprintf (stderr, "?Invalid rmt response code: %c\n",rc);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* get numeric value (returned by both A and E responses) */
|
||||
for (n=0;;)
|
||||
{
|
||||
doread (mtape->tapefd, &c, 1); /* get next digit */
|
||||
if (c < '0' || c > '9')
|
||||
break; /* not a digit */
|
||||
n = n * 10 + (c - '0'); /* add new digit in */
|
||||
/* ideally would check for overflow */
|
||||
}
|
||||
if (c != '\n')
|
||||
{ /* first non-digit char must be <LF> */
|
||||
fprintf (stderr, "?Invalid rmt response terminator: %3.3o\n",
|
||||
((int) c) & 0377);
|
||||
exit (1);
|
||||
}
|
||||
if (rc == 'A')
|
||||
return (n); /* success, return value >=0 */
|
||||
/* (unless overflowed) */
|
||||
do
|
||||
doread (mtape->tapefd, &c, 1);
|
||||
while (c != '\n'); /* ignore until next LF */
|
||||
errno = n; /* set error number */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* send ioctl() command to local or remote tape drive */
|
||||
static int doioctl (tape_handle mtape, struct mtop *op)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (mtape->tape_type == TT_TAPE)
|
||||
return (ioctl (mtape->tapefd, MTIOCTOP, op));
|
||||
else
|
||||
{ /* "rmt" tape server */
|
||||
/* form cmd (better hope remote MT_OP values are the same) */
|
||||
len = sprintf (mtape->netbuf, "I%d\n%d\n", op->mt_op, op->mt_count);
|
||||
dowrite (mtape->tapefd, mtape->netbuf, len);
|
||||
return (response (mtape));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* open the tape drive (or whatever) */
|
||||
/* "create" =1 to create if file, "writable" =1 to open with write access */
|
||||
tape_handle opentape (char *name, int create, int writable)
|
||||
{
|
||||
char *p, *user, *port;
|
||||
int len;
|
||||
char *host = NULL;
|
||||
|
||||
tape_handle mtape = NULL;
|
||||
|
||||
mtape = (tape_handle) calloc (1, sizeof (struct mtape_t));
|
||||
if (! mtape)
|
||||
FAIL ("?can't allocate mtape struct\n");
|
||||
|
||||
mtape->bpi = BPI;
|
||||
|
||||
mtape->waccess = writable; /* remember if we're writing */
|
||||
mtape->count = 0; /* nothing transferred yet */
|
||||
|
||||
/* get tape filename */
|
||||
if (name == NULL)
|
||||
name = getenv("TAPE"); /* get from environment */
|
||||
if (name == NULL)
|
||||
name = TAPE; /* or use our default */
|
||||
|
||||
/* just a file if no colon in filename */
|
||||
if ((p = index (name, ':')) == NULL)
|
||||
{
|
||||
/* there's probably a better way to handle this, in case a file is really
|
||||
a link to a tape drive -- handler index or something? */
|
||||
if (strncmp (name, "/dev/", 5) == 0)
|
||||
{
|
||||
/* assume tape if starts with /dev/ */
|
||||
mtape->tape_type = TT_TAPE;
|
||||
mtape->tapefd = open (name, (writable ? O_RDWR : O_RDONLY), 0);
|
||||
}
|
||||
else
|
||||
{ /* otherwise file */
|
||||
mtape->tape_type = TT_IMAGE;
|
||||
if (strcmp (name, "-") ==0 )
|
||||
{ /* stdin/stdout */
|
||||
if (writable)
|
||||
mtape->tapefd=1;
|
||||
else
|
||||
mtape->tapefd=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (create)
|
||||
mtape->tapefd = open (name, O_CREAT | O_TRUNC |
|
||||
O_WRONLY | O_BINARY, 0644);
|
||||
else
|
||||
{
|
||||
mtape->tapefd = open (name, (writable ? O_RDWR : O_RDONLY) |
|
||||
O_BINARY, 0);
|
||||
mtape->seek_ok = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mtape->tapefd < 0)
|
||||
FAIL ("?can't open device or file\n");
|
||||
}
|
||||
else
|
||||
{ /* "rmt" tape server on remote host */
|
||||
mtape->tape_type = TT_RMT;
|
||||
/* split filename around ':' */
|
||||
len = p-name;
|
||||
port = p+1;
|
||||
|
||||
/* can't necessarily modify tape[] so copy it first */
|
||||
if ((host = malloc (len + 1)) == NULL)
|
||||
FAIL ("?can't allocate string for hostname\n");
|
||||
strncpy (host, name, len); /* copy hostname */
|
||||
host [len] = 0; /* tack on null */
|
||||
|
||||
/* connect to "rexec" server */
|
||||
if ((p = index (host, '@')) == NULL)
|
||||
{
|
||||
p = host; /* no @, point at hostname */
|
||||
user = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = '\0'; /* shoot out @, point at host name */
|
||||
user = (*p != '\0') ? host : NULL; /* keep non-null user */
|
||||
}
|
||||
if ((mtape->tapefd = rexec (&p, htons (512), user, NULL, "/etc/rmt",
|
||||
(int *) NULL)) < 0)
|
||||
FAIL ("?Connection failed\n");
|
||||
|
||||
/* build rmt "open device" command */
|
||||
if ((1 + strlen (port) + 1 + 1 + 1 + 1) > sizeof (mtape->netbuf))
|
||||
FAIL ("?Device name too long\n");
|
||||
len = sprintf (mtape->netbuf, "O%s\n%d\n", port, writable ? O_RDWR : O_RDONLY);
|
||||
dowrite (mtape->tapefd, mtape->netbuf, len);
|
||||
if (response (mtape) < 0)
|
||||
FAIL ("?Error opening tape drive");
|
||||
}
|
||||
|
||||
/* SCSI setup for local/remote tape drive */
|
||||
if ((mtape->tape_type == TT_TAPE) ||
|
||||
(mtape->tape_type == TT_RMT))
|
||||
{
|
||||
/* (ignore errors in case not SCSI) */
|
||||
/* set variable record length mode */
|
||||
doioctl (mtape, & mt_setblk);
|
||||
/* set density to 1600 */
|
||||
doioctl (mtape, & mt_setden);
|
||||
}
|
||||
|
||||
if (host)
|
||||
free (host);
|
||||
|
||||
return (mtape);
|
||||
|
||||
fail:
|
||||
if (mtape)
|
||||
{
|
||||
if (host)
|
||||
free (host);
|
||||
free (mtape);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
/* close the tape drive */
|
||||
void closetape (tape_handle mtape)
|
||||
{
|
||||
if (mtape->waccess)
|
||||
{ /* opened for create/append */
|
||||
tapemark (mtape); /* add one more tape mark */
|
||||
/* (should have one already) */
|
||||
}
|
||||
if (mtape->tape_type == TT_RMT)
|
||||
{
|
||||
dowrite (mtape->tapefd, "C\n", 2);
|
||||
if (response (mtape) < 0)
|
||||
{
|
||||
perror("?Error closing remote tape");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (close (mtape->tapefd) < 0)
|
||||
{
|
||||
perror("?Error closing tape");
|
||||
exit(1);
|
||||
}
|
||||
free (mtape);
|
||||
}
|
||||
|
||||
|
||||
/* rewind tape */
|
||||
void posnbot (tape_handle mtape)
|
||||
{
|
||||
if (mtape->tape_type == TT_IMAGE)
|
||||
{ /* image file */
|
||||
if (lseek (mtape->tapefd, 0L, SEEK_SET) < 0)
|
||||
{
|
||||
perror("?Seek failed");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* local/remote tape drive */
|
||||
if (doioctl (mtape, & mt_rew) < 0)
|
||||
{
|
||||
perror("?Rewind failed");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* position tape at EOT (between the two tape marks) */
|
||||
void posneot (tape_handle mtape)
|
||||
{
|
||||
if (mtape->tape_type == TT_IMAGE)
|
||||
{ /* image file */
|
||||
if (lseek (mtape->tapefd, -4L, SEEK_END) < 0)
|
||||
{
|
||||
perror("?Seek failed");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* local/remote tape drive */
|
||||
doioctl (mtape, & mt_bsr); /* in case already at LEOT */
|
||||
while (1)
|
||||
{
|
||||
/* space forward a file */
|
||||
if (doioctl (mtape, & mt_fsf) < 0)
|
||||
{
|
||||
perror("?Error spacing to EOT");
|
||||
exit(1);
|
||||
}
|
||||
/* space one record more to see if double EOF */
|
||||
if (doioctl (mtape, & mt_fsr) < 0)
|
||||
break;
|
||||
/* might want to check errno to make sure it's the right error */
|
||||
}
|
||||
#if 1
|
||||
/* "man mtio" doesn't say whether MTFSR actually moves past */
|
||||
/* the tape mark, let's assume it does */
|
||||
if (doioctl (mtape, & mt_bsr) < 0)
|
||||
{ /* get between them */
|
||||
perror("?Error backspacing at EOT");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* read a tape record, return actual length (0=tape mark) */
|
||||
int getrec (tape_handle mtape, char *buf, int len)
|
||||
{
|
||||
unsigned char byte [4]; /* 32 bits for length field(s) */
|
||||
unsigned long l; /* at least 32 bits */
|
||||
|
||||
if (mtape->tape_type == TT_IMAGE)
|
||||
{ /* image file */
|
||||
doread (mtape->tapefd, byte, 4); /* get record length */
|
||||
l=((unsigned long)byte[3]<<24L)|((unsigned long)byte[2]<<16L)|
|
||||
((unsigned long)byte[1]<<8L)|(unsigned long)byte[0];
|
||||
/* compose into longword */
|
||||
if (l > len)
|
||||
goto toolong; /* don't read if too long for buf */
|
||||
if (l != 0)
|
||||
{ /* get data unless tape mark */
|
||||
doread (mtape->tapefd, buf, l); /* read data */
|
||||
doread (mtape->tapefd, byte, 4); /* get trailing record length */
|
||||
if((((unsigned long)byte[3]<<24L)|
|
||||
((unsigned long)byte[2]<<16L)|
|
||||
((unsigned long)byte[1]<<8)|
|
||||
(unsigned long)byte[0])!=l)
|
||||
{ /* should match */
|
||||
fprintf (stderr,"?Corrupt tape image\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mtape->tape_type == TT_RMT)
|
||||
{ /* rmt tape server */
|
||||
len = sprintf (mtape->netbuf, "R%d\n", len);
|
||||
dowrite (mtape->tapefd, mtape->netbuf, len);
|
||||
if ((l = response (mtape)) < 0)
|
||||
{
|
||||
perror("?Error reading tape");
|
||||
exit(1);
|
||||
}
|
||||
if (l)
|
||||
doread (mtape->tapefd, buf, l);
|
||||
}
|
||||
else
|
||||
{ /* local tape drive */
|
||||
if ((l = read (mtape->tapefd, buf, len)) < 0)
|
||||
{
|
||||
perror("?Error reading tape");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
return(l);
|
||||
|
||||
toolong:
|
||||
fprintf(stderr,"?%ld byte tape record too long for %d byte buffer\n",
|
||||
l,len);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* write a tape record */
|
||||
void putrec (tape_handle mtape, char *buf, int len)
|
||||
{
|
||||
unsigned char l [4];
|
||||
|
||||
if (mtape->tape_type == TT_IMAGE)
|
||||
{ /* image file */
|
||||
l [0] = len & 0377; /* PDP-11 byte order */
|
||||
l [1] = (len >> 8) &0377;
|
||||
l [2] = 0; /* our recs are always < 64 KB */
|
||||
l [3] = 0;
|
||||
dowrite (mtape->tapefd, l, 4); /* write longword length */
|
||||
dowrite (mtape->tapefd, buf, len); /* write data */
|
||||
dowrite (mtape->tapefd, l, 4); /* write length again */
|
||||
}
|
||||
else if (mtape->tape_type == TT_RMT)
|
||||
{ /* rmt tape */
|
||||
int n;
|
||||
n = sprintf (mtape->netbuf, "W%d\n", len);
|
||||
dowrite (mtape->tapefd, mtape->netbuf, n);
|
||||
dowrite (mtape->tapefd, buf, len);
|
||||
}
|
||||
else
|
||||
dowrite (mtape->tapefd, buf, len); /* just write the data if tape */
|
||||
|
||||
mtape->count += len + (mtape->bpi * 3 /5); /* add to byte count
|
||||
(+0.6" tape gap) */
|
||||
}
|
||||
|
||||
|
||||
/* write a tape mark */
|
||||
void tapemark (tape_handle mtape)
|
||||
{
|
||||
static char zero [4] = { 0, 0, 0, 0 };
|
||||
|
||||
if (mtape->tape_type == TT_IMAGE)
|
||||
{ /* image file */
|
||||
dowrite (mtape->tapefd, zero, 4); /* write longword length */
|
||||
}
|
||||
else
|
||||
{ /* local/remote tape drive */
|
||||
if (doioctl (mtape, & mt_weof) < 0)
|
||||
{
|
||||
perror ("?Failed writing tape mark");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
mtape->count += 3 * mtape->bpi; /* 3" of tape */
|
||||
}
|
||||
|
||||
|
||||
/* skip records (negative for reverse) */
|
||||
void skiprec (tape_handle mtape, int count)
|
||||
{
|
||||
unsigned char byte [4]; /* 32 bits for length field(s) */
|
||||
unsigned long l; /* at least 32 bits */
|
||||
|
||||
if (mtape->tape_type != TT_IMAGE)
|
||||
{
|
||||
fprintf (stderr, "?Record skip only implemented for image files");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
fprintf (stderr, "?Record skip reverse not yet implemented");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
doread (mtape->tapefd, byte, 4); /* get record length */
|
||||
|
||||
/* compose into longword */
|
||||
l=((unsigned long)byte[3]<<24L)|((unsigned long)byte[2]<<16L)|
|
||||
((unsigned long)byte[1]<<8L)|(unsigned long)byte[0];
|
||||
|
||||
if (l == 0) /* hit tape mark? */
|
||||
return; /* note that we've effectively skipped over the tape mark */
|
||||
|
||||
/* skip record */
|
||||
if (lseek (mtape->tapefd, l, SEEK_CUR) < 0)
|
||||
{
|
||||
perror ("?Seek failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
doread (mtape->tapefd, byte, 4); /* get trailing record length */
|
||||
if((((unsigned long)byte[3]<<24L)|
|
||||
((unsigned long)byte[2]<<16L)|
|
||||
((unsigned long)byte[1]<<8)|
|
||||
(unsigned long)byte[0])!=l)
|
||||
{ /* should match */
|
||||
fprintf (stderr,"?Corrupt tape image\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* skip forward to the next file mark, and leave the tape positioned
|
||||
after the mark */
|
||||
static void skip_to_mark (tape_handle mtape)
|
||||
{
|
||||
unsigned char byte [4]; /* 32 bits for length field(s) */
|
||||
unsigned long l; /* at least 32 bits */
|
||||
|
||||
static char scratch_buf [4096];
|
||||
|
||||
if (mtape->tape_type != TT_IMAGE)
|
||||
{
|
||||
fprintf (stderr, "?Record skip only implemented for image files");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
doread (mtape->tapefd, byte, 4); /* get record length */
|
||||
|
||||
/* compose into longword */
|
||||
l=((unsigned long)byte[3]<<24L)|((unsigned long)byte[2]<<16L)|
|
||||
((unsigned long)byte[1]<<8L)|(unsigned long)byte[0];
|
||||
|
||||
if (l == 0) /* hit tape mark? */
|
||||
return; /* note that we've effectively skipped over the tape mark */
|
||||
|
||||
/* skip record */
|
||||
if (mtape->seek_ok)
|
||||
{
|
||||
if (lseek (mtape->tapefd, l, SEEK_CUR) < 0)
|
||||
{
|
||||
perror ("?Seek failed");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int len, len2;
|
||||
len = l;
|
||||
while (len > 0)
|
||||
{
|
||||
len2 = len;
|
||||
if (len2 > sizeof (scratch_buf))
|
||||
len2 = sizeof (scratch_buf);
|
||||
doread (mtape->tapefd, scratch_buf, len2); /* read data */
|
||||
len -= len2;
|
||||
}
|
||||
}
|
||||
|
||||
doread (mtape->tapefd, byte, 4); /* get trailing record length */
|
||||
if((((unsigned long)byte[3]<<24L)|
|
||||
((unsigned long)byte[2]<<16L)|
|
||||
((unsigned long)byte[1]<<8)|
|
||||
(unsigned long)byte[0])!=l)
|
||||
{ /* should match */
|
||||
fprintf (stderr,"?Corrupt tape image\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* skip files (negative for reverse) */
|
||||
void skipfile (tape_handle mtape, int count)
|
||||
{
|
||||
if (mtape->tape_type != TT_IMAGE)
|
||||
{
|
||||
fprintf (stderr, "?File skip only implemented for image files");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
fprintf (stderr, "?File skip reverse not yet implemented");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
skip_to_mark (mtape);
|
||||
}
|
||||
}
|
||||
|
||||
53
tapeio.h
Normal file
53
tapeio.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
Routines to do magtape I/O to local tapes, remote tapes, and tape image
|
||||
files.
|
||||
|
||||
Copyright 1998, 1999 John Wilson and Eric Smith
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as published
|
||||
by the Free Software Foundation. Note that permission is not granted
|
||||
to redistribute this program under the terms of any other version of the
|
||||
General Public License.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct mtape_t *tape_handle; /* opaque type */
|
||||
|
||||
|
||||
/* open a tape drive */
|
||||
tape_handle opentape (char *name, int create, int writable);
|
||||
|
||||
/* close a tape drive */
|
||||
void closetape (tape_handle h);
|
||||
|
||||
/* rewind tape */
|
||||
void posnbot (tape_handle h);
|
||||
|
||||
/* position tape at EOT (between the two tape marks) */
|
||||
void posneot (tape_handle h);
|
||||
|
||||
/* read a tape record, return actual length (0=tape mark) */
|
||||
int getrec (tape_handle h, char *buf, int len);
|
||||
|
||||
/* write a tape record */
|
||||
void putrec (tape_handle h, char *buf, int len);
|
||||
|
||||
/* write a tape mark */
|
||||
void tapemark (tape_handle h);
|
||||
|
||||
/* skip records (negative for reverse) */
|
||||
void skiprec (tape_handle h, int count);
|
||||
|
||||
/* skip files (negative for reverse) */
|
||||
void skipfile (tape_handle h, int count);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user