From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 19-JUN-1991 12:07:37.21
To:	ARISIA::EVERHART
CC:	
Subj:	unix util 2 read vms backup (summary)

From:	RELAY-INFO-VAX@CRVAX.SRI.COM@SMTP@CRDGW2
To:	Everhart@Arisia@MRGATE

Received:  by crdgw1.ge.com (5.57/GE 1.100)
	 id AA21506; Tue, 18 Jun 91 18:29:29 EDT
Message-Id:  <9106182229.AA21506@crdgw1.ge.com>
Received: From omdc ([131.128.100.27]) by CRVAX.SRI.COM with TCP; Tue, 18 JUN 91 11:11:11 PDT
Date: 18 Jun 91 13:33:00 EST
From: "DUMMY ACCOUNT FOR COMMON USE" <seabeam@omdc.gso.uri.edu>
Subject: unix util 2 read vms backup (summary)
To: "info-vax" <info-vax@sri.com>


Here is a summery of replies to my question on reading vms backups from unix.
-Gerry 

*******************************************************************************


	Some time ago I found the following VMSShare-file in INFO-VAX.
I am not sure if it is the thing you are looking for, as I have not
tested it myself. Good luck.

		Lejf.

	----------------------------------------------------------
	Lejf Rasmussen
	Psykologisk Laboratorium, Koebenhavns Universitet, Amager,
	Njalsgade 88, DK 2300 Koebenhavn S, Danmark.
	Email: lejf@vax.psl.ku.dk
	Phone: 31 54 22 11, ext 2515.		Fax: 32 96 31 38
	__________________________________________________________

Cut Here+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
From:	IN%"usc!zaphod.mps.ohio-state.edu!think.com!linus!philabs!axh@apple.com" 27-FEB-1991 01:07:00.14
To:	info-vax@kl.sri.com
CC:	
Subj:	VMSBACKUP V4.0 PART 1/1

Hi everyone,
	Over the past few days I have received too many requests
for the vmsbackup version 4.0 program. I thought the best solution
is to post it on the net, as the program itself isn't that big and
would also save my time. I got this program from David Kinney, and
would thank him again for the help.

- Abid.

#--------------------------------CUT HERE-------------------------------------
#!/bin/sh
#
# This is a shell archive.  Save this into a file, edit it and delete all
# lines through the line "CUT HERE" (above). Then give this file to sh by
# executing the command "sh file".  The files will be extracted into the
# current directory owned by you with default permissions.
#
# The files contained herein are:
#
# -rw-rw-r--  1 dkinney       299 May 22  1990 Makefile
# -rw-r--r--  1 dkinney       605 May 22  1990 Makefile.orig
# -rw-rw-r--  1 dkinney       573 May 22  1990 README
# -rw-rw-r--  1 dkinney      2048 May 22  1990 getopt.1
# -rw-rw-r--  1 dkinney      3561 May 22  1990 getopt.c
# -rw-rw-r--  1 dkinney      8100 May 22  1990 match.c
# -rw-rw-r--  1 dkinney      3528 May 22  1990 vmsbackup.1
# -rw-rw-r--  1 dkinney     24995 May 22  1990 vmsbackup.c
# -rw-rw-r--  1 dkinney      4304 Jun 19  1990 vmsbackup.doc
#
echo 'x - Makefile'
if test -f Makefile; then echo 'shar: not overwriting Makefile'; else
sed 's/^X//' << '________This_Is_The_END________' > Makefile
X#
X#
XREMOTE= 	                # -DREMOTE  use remote tape
XSWAP=                           # -DSWAP swap bytes
XCFLAGS= $(SWAP) $(REMOTE)
XLFLAGS=
XLIBS=                           # remote magtape library
XCC = cc
X#
Xvmsbackup: vmsbackup.o match.o
X	$(CC) $(LFLAGS) -o vmsbackup vmsbackup.o match.o $(LIBS)
________This_Is_The_END________
if test `wc -l < Makefile` -ne 11; then
	echo 'shar: Makefile was damaged during transit (should have been 11 bytes)'
fi
fi		; : end of overwriting check
echo 'x - Makefile.orig'
if test -f Makefile.orig; then echo 'shar: not overwriting Makefile.orig'; else
sed 's/^X//' << '________This_Is_The_END________' > Makefile.orig
X#
X#
XREMOTE=-DREMOTE			# -DREMOTE  use remote tape
XSWAP=				# -DSWAP swap bytes
XCFLAGS= $(SWAP) $(REMOTE)
XLFLAGS=
XLIBS= -lrmt   			# remote magtape library
XOWNER=tar			# user for remote tape access
XMODE=4755
XBINDIR=/usr/local/bin
XMANSEC=l
XMANDIR=/usr/man/man$(MANSEC)
X
X#
Xvmsbackup: vmsbackup.o getopt.o match.o
X	cc $(LFLAGS) -o vmsbackup vmsbackup.o match.o getopt.o $(LIBS)
Xinstall:
X	install -m $(MODE) -o $(OWNER) -s vmsbackup $(BINDIR)	
X	cp vmsbackup.1 $(MANDIR)/vmsbackup.$(MANSEC)
Xclean:
X	rm -f vmsbackup *.o core
Xshar:
X	shar -a README vmsbackup.1 Makefile vmsbackup.c match.c \
X	    > vmsbackup.shar
________This_Is_The_END________
if test `wc -l < Makefile.orig` -ne 24; then
	echo 'shar: Makefile.orig was damaged during transit (should have been 24 bytes)'
fi
fi		; : end of overwriting check
echo 'x - README'
if test -f README; then echo 'shar: not overwriting README'; else
sed 's/^X//' << '________This_Is_The_END________' > README
XThis progam reads a VMS backuptape.
X
XThe tape program is orginally written by John Douglas Carey and
Xthe pattern matching routine by some unknown on the net.
X
XThe remote tape option use the rmtlib from mod.sources.
X
XA good way to archive remotetape access for users with only
Xa local account is to create a "netwide" user tar and let
Xthe remote tape programs do suid to user tar.
X
XThe program is tested on vax and sun.
X
X
XSven-Ove Westberg
XLulea University of Technology
XS-951 87  Lulea,  Sweden
XUUCP:  sow@luthcad.UUCP
XUUCP:  {decvax,philabs,seismo}!mcvax!enea!luthcad!sow
________This_Is_The_END________
if test `wc -l < README` -ne 19; then
	echo 'shar: README was damaged during transit (should have been 19 bytes)'
fi
fi		; : end of overwriting check
echo 'x - getopt.1'
if test -f getopt.1; then echo 'shar: not overwriting getopt.1'; else
sed 's/^X//' << '________This_Is_The_END________' > getopt.1
X.TH GETOPT 1 LOCAL
X.SH NAME
Xgetopt \- format flags for shell scripts
X.SH SYNOPSIS
X.B getopt
Xflag_spec argument ...
X.SH DESCRIPTION
X.I Getopt
Xis a program intended to be called by scripts to ``canonicalize'' their
Xarguments before processing them, just as the
X.IR getopt (3)
Xroutine does for C programs.
X(This need for scripts is usually most noticeable in the way
X.IR lint (1)
Xhandles the
X.B \-n
Xflag.)
X.PP
XThe following two examples provide the initial parsing for a script
Xwhich takes two flags,
X.B \-a
Xand
X.BR \-b ,
Xthe second of which takes an argument.
X.RS
X.ta +4n +4n +4n +4n
X.nf
X# For /bin/csh...
Xset argv = (`getopt "ab:" $*`)
Xif ( $status ) then
X        echo "Read the documentation and try again." >/dev/tty
X        exit 1
Xendif
Xset Aflag=0
Xset Name=NONE
Xwhile "$1" != "--"
X        switch ("$1")
X                case '-a':
X                        set Aflag=1
X                        breaksw
X                case '-b':
X                        shift
X                        set Name=$1
X                        breaksw
X        endsw
X        shift
Xend
Xshift
Xecho Aflag=$Aflag / Name=$Name / Remaining args are $*
X
X# For /bin/sh...
Xset -- `getopt "d:s" $@`
Xif test $? != 0 ; then
X        echo "Read the documentation and try again."
X        exit 1
Xfi
XAflag=0
XName=NONE
Xfor f
Xdo
X        case "$f" in
X                -a)     Aflag=1
X                        ;;
X                -b)     shift
X                        Name=$2
X                        ;;
X                --)     break
X                        ;;
X        esac
X        shift
Xdone
Xshift
Xecho Aflag=$Aflag / Name=$Name / Remaining args are $*
X.fi
X.RE
X.SH DIAGNOSTICS
XThe program burps the standard
X.IR getopt (3)
Xdiagnostics to standard error, and exits with a non-zero status if an
Xerror occurs.
XIt is arguable wrong that the diagnostics imply that the program
Xis named ``getopt'' rather than the real name of the script.
XIt is undeniably AT&T\-compatible to do this, however.
X.SH "SEE ALSO"
Xcsh(1), sh(1), getopt(3)
X.SH AUTHOR
X.nf
XRich $alz
XMirror Systems
X(mirror!rs, rs@mirror.TMC.COM)
________This_Is_The_END________
if test `wc -l < getopt.1` -ne 90; then
	echo 'shar: getopt.1 was damaged during transit (should have been 90 bytes)'
fi
fi		; : end of overwriting check
echo 'x - getopt.c'
if test -f getopt.c; then echo 'shar: not overwriting getopt.c'; else
sed 's/^X//' << '________This_Is_The_END________' > getopt.c
X/*
X**  GETOPT PROGRAM AND LIBRARY ROUTINE
X**
X**  I wrote main() and AT&T wrote getopt() and we both put our efforts into
X**  the public domain via mod.sources.
X**      Rich $alz
X**      Mirror Systems
X**      (mirror!rs, rs@mirror.TMC.COM)
X**      August 10, 1986
X*/
X
X#include <stdio.h>
X
X
X#ifndef INDEX
X#define INDEX index
X#endif
X
X
Xextern char     *INDEX();
Xextern int       optind;
Xextern char     *optarg;
X
X
Xmain(ac, av)
X    register int         ac;
X    register char       *av[];
X{
X    register char       *flags;
X    register int         c;
X
X    /* Check usage. */
X    if (ac < 2) {
X        fprintf(stderr, "usage: %s flag-specification arg-list\n", av[0]);
X        exit(2);
X    }
X
X    /* Play games; remember the flags (first argument), then splice
X       them out so it looks like a "standard" command vector. */
X    flags = av[1];
X    av[1] = av[0];
X    av++;
X    ac--;
X
X    /* Print flags. */
X    while ((c = getopt(ac, av, flags)) != EOF) {
X        if (c == '?')
X            exit(1);
X        /* We assume that shells collapse multiple spaces in `` expansion. */
X        printf("-%c %s ", c, INDEX(flags, c)[1] == ':' ? optarg : "");
X    }
X
X    /* End of flags; print rest of options. */
X    printf("-- ");
X    for (av += optind; *av; av++)
X        printf("%s ", *av);
X    exit(0);
X}
X
X
X
X
X
X
X
X
X
X/*
X**  This is the public-domain AT&T getopt(3) code.  I added the
X**  #ifndef stuff because I include <stdio.h> for the program;
X**  getopt, per se, doesn't need it.  I also added the INDEX/index
X**  hack (the original used strchr, of course).  And, note that
X**  technically the casts in the write(2) calls shouldn't be there.
X*/
X
X#ifndef NULL
X#define NULL    0
X#endif
X#ifndef EOF
X#define EOF     (-1)
X#endif
X#ifndef INDEX
X#define INDEX index
X#endif
X
X
X#define ERR(s, c)       if(opterr){\
X        extern int strlen(), write();\
X        char errbuf[2];\
X        errbuf[0] = c; errbuf[1] = '\n';\
X        (void) write(2, argv[0], (unsigned)strlen(argv[0]));\
X        (void) write(2, s, (unsigned)strlen(s));\
X        (void) write(2, errbuf, 2);}
X
Xextern int strcmp();
Xextern char *INDEX();
X
Xint     opterr = 1;
Xint     optind = 1;
Xint     optopt;
Xchar    *optarg;
X
Xint
Xgetopt(argc, argv, opts)
Xint     argc;
Xchar    **argv, *opts;
X{
X        static int sp = 1;
X        register int c;
X        register char *cp;
X
X        if(sp == 1)
X                if(optind >= argc ||
X                   argv[optind][0] != '-' || argv[optind][1] == '\0')
X                        return(EOF);
X                else if(strcmp(argv[optind], "--") == NULL) {
X                        optind++;
X                        return(EOF);
X                }
X        optopt = c = argv[optind][sp];
X        if(c == ':' || (cp=INDEX(opts, c)) == NULL) {
X                ERR(": illegal option -- ", c);
X                if(argv[optind][++sp] == '\0') {
X                        optind++;
X                        sp = 1;
X                }
X                return('?');
X        }
X        if(*++cp == ':') {
X                if(argv[optind][sp+1] != '\0')
X                        optarg = &argv[optind++][sp+1];
X                else if(++optind >= argc) {
X                        ERR(": option requires an argument -- ", c);
X                        sp = 1;
X                        return('?');
X                } else
X                        optarg = argv[optind++];
X                sp = 1;
X        } else {
X                if(argv[optind][++sp] == '\0') {
X                        sp = 1;
X                        optind++;
X                }
X                optarg = NULL;
X        }
X        return(c);
X}
________This_Is_The_END________
if test `wc -l < getopt.c` -ne 147; then
	echo 'shar: getopt.c was damaged during transit (should have been 147 bytes)'
fi
fi		; : end of overwriting check
echo 'x - match.c'
if test -f match.c; then echo 'shar: not overwriting match.c'; else
sed 's/^X//' << '________This_Is_The_END________' > match.c
X#include <stdio.h>
X#include <sys/types.h>
X
X#define ASTERISK '*'            /* The '*' metacharacter */
X#define QUESTION '?'            /* The '?' metacharacter */
X#define LEFT_BRACKET '['        /* The '[' metacharacter */
X#define RIGHT_BRACKET ']'       /* The ']' metacharacter */
X
X#define IS_OCTAL(ch) (ch >= '0' && ch <= '7')
X
Xtypedef int BOOLEAN;
X#define VOID void
X#define TRUE 1
X#define FALSE 0
X#define EOS '\000'
X
Xstatic BOOLEAN do_list ();
Xstatic char nextch ();
Xstatic VOID list_parse ();
X
X
X
X
X
X
X
X
X
X/*
X *  FUNCTION
X *
X *      match   test string for wildcard match
X *
X *  SYNOPSIS
X *
X *      BOOLEAN match (string, pattern)
X *      register char *string;
X *      register char *pattern;
X *
X *  DESCRIPTION
X *
X *      Test string for match using pattern.  The pattern may
X *      contain the normal shell metacharacters for pattern
X *      matching.  The '*' character matches any string,
X *      including the null string.  The '?' character matches
X *      any single character.  A list of characters enclosed
X *      in '[' and ']' matches any character in the list.
X *      If the first character following the beginning '['
X *      is a '!' then any character not in the list is matched.
X *
X */
X
X
X
X
X
X
X
X
X
X/*
X *  PSEUDO CODE
X *
X *      Begin match
X *          Switch on type of pattern character
X *              Case ASTERISK:
X *                  Attempt to match asterisk
X *                  Break
X *              Case QUESTION MARK:
X *                  Attempt to match question mark
X *                  Break
X *              Case EOS:
X *                  Match is result of EOS on string test
X *                  Break
X *              Case default:
X *                  If explicit match then
X *                      Match is result of submatch
X *                  Else
X *                      Match is FALSE
X *                  End if
X *                  Break
X *          End switch
X *          Return result of match test
X *      End match
X *
X */
X
XBOOLEAN match (string, pattern)
Xregister char *string;
Xregister char *pattern;
X{
X    register BOOLEAN ismatch;
X
X    ismatch = FALSE;
X    switch (*pattern) {
X        case ASTERISK:
X            pattern++;
X            do {
X                ismatch = match (string, pattern);
X            } while (!ismatch && *string++ != EOS);
X            break;
X        case QUESTION:
X            if (*string != EOS) {
X                ismatch = match (++string, ++pattern);
X            }
X            break;
X        case EOS:
X            if (*string == EOS) {
X                ismatch = TRUE;
X            }
X            break;
X        case LEFT_BRACKET:
X            if (*string != EOS) {
X                ismatch = do_list (string, pattern);
X            }
X            break;
X        default:
X            if (*string++ == *pattern++) {
X                ismatch = match (string, pattern);
X            } else {
X                ismatch = FALSE;
X            }
X            break;
X    }
X    return (ismatch);
X}
X
X
X
X
X
X
X
X
X
X/*
X *  FUNCTION
X *
X *      do_list    process a list and following substring
X *
X *  SYNOPSIS
X *
X *      static BOOLEAN do_list (string, pattern)
X *      register char *string;
X *      register char *pattern;
X *
X *  DESCRIPTION
X *
X *      Called when a list is found in the pattern.  Returns
X *      TRUE if the current character matches the list and
X *      the remaining substring matches the remaining pattern.
X *
X *      Returns FALSE if either the current character fails to
X *      match the list or the list matches but the remaining
X *      substring and subpattern's don't.
X *
X *  RESTRICTIONS
X *
X *      The mechanism used to match characters in an inclusive
X *      pair (I.E. [a-d]) may not be portable to machines
X *      in which the native character set is not ASCII.
X *
X *      The rules implemented here are:
X *
X *              (1)     The backslash character may be
X *                      used to quote any special character.
X *                      I.E.  "\]" and "\-" anywhere in list,
X *                      or "\!" at start of list.
X *
X *              (2)     The sequence \nnn becomes the character
X *                      given by nnn (in octal).
X *
X *              (3)     Any non-escaped ']' marks the end of list.
X *
X *              (4)     A list beginning with the special character
X *                      '!' matches any character NOT in list.
X *                      The '!' character is only special if it
X *                      is the first character in the list.
X *
X */
X
X
X
X
X
X
X
X
X
X/*
X *  PSEUDO CODE
X *
X *      Begin do_list
X *          Default result is no match
X *          Skip over the opening left bracket
X *          If the next pattern character is a '!' then
X *              List match gives FALSE
X *              Skip over the '!' character
X *          Else
X *              List match gives TRUE
X *          End if
X *          While not at closing bracket or EOS
X *              Get lower and upper bounds
X *              If character in bounds then
X *                  Result is same as sense flag.
X *                  Skip over rest of list
X *              End if
X *          End while
X *          If match found then
X *              If not at end of pattern then
X *                  Call match with rest of pattern
X *              End if
X *          End if
X *          Return match result
X *      End do_list
X *
X */
X
Xstatic BOOLEAN do_list (string, pattern)
Xregister char *string;
Xchar *pattern;
X{
X    register BOOLEAN ismatch;
X    register BOOLEAN if_found;
X    register BOOLEAN if_not_found;
X    auto char lower;
X    auto char upper;
X
X    pattern++;
X    if (*pattern == '!') {
X        if_found = FALSE;
X        if_not_found = TRUE;
X        pattern++;
X    } else {
X        if_found = TRUE;
X        if_not_found = FALSE;
X    }
X    ismatch = if_not_found;
X    while (*pattern != ']' && *pattern != EOS) {
X        list_parse (&pattern, &lower, &upper);
X        if (*string >= lower && *string <= upper) {
X            ismatch = if_found;
X            while (*pattern != ']' && *pattern != EOS) {pattern++;}
X        }
X    }
X    if (*pattern++ != ']') {
X        fprintf (stderr, "warning - character class error\n");
X    } else {
X        if (ismatch) {
X            ismatch = match (++string, pattern);
X        }
X    }
X    return (ismatch);
X}
X
X
X
X
X
X
X
X
X
X/*
X *  FUNCTION
X *
X *      list_parse    parse part of list into lower and upper bounds
X *
X *  SYNOPSIS
X *
X *      static VOID list_parse (patp, lowp, highp)
X *      char **patp;
X *      char *lowp;
X *      char *highp;
X *
X *  DESCRIPTION
X *
X *      Given pointer to a pattern pointer (patp), pointer to
X *      a place to store lower bound (lowp), and pointer to a
X *      place to store upper bound (highp), parses part of
X *      the list, updating the pattern pointer in the process.
X *
X *      For list characters which are not part of a range,
X *      the lower and upper bounds are set to that character.
X *
X */
X
Xstatic VOID list_parse (patp, lowp, highp)
Xchar **patp;
Xchar *lowp;
Xchar *highp;
X{
X    *lowp = nextch (patp);
X    if (**patp == '-') {
X        (*patp)++;
X        *highp = nextch (patp);
X    } else {
X        *highp = *lowp;
X    }
X}
X
X
X
X
X
X
X
X
X
X/*
X *  FUNCTION
X *
X *      nextch    determine next character in a pattern
X *
X *  SYNOPSIS
X *
X *      static char nextch (patp)
X *      char **patp;
X *
X *  DESCRIPTION
X *
X *      Given pointer to a pointer to a pattern, uses the pattern
X *      pointer to determine the next character in the pattern,
X *      subject to translation of backslash-char and backslash-octal
X *      sequences.
X *
X *      The character pointer is updated to point at the next pattern
X *      character to be processed.
X *
X */
X
Xstatic char nextch (patp)
Xchar **patp;
X{
X    register char ch;
X    register char chsum;
X    register int count;
X
X    ch = *(*patp)++;
X    if (ch == '\\') {
X        ch = *(*patp)++;
X        if (IS_OCTAL (ch)) {
X            chsum = 0;
X            for (count = 0; count < 3 && IS_OCTAL (ch); count++) {
X                chsum *= 8;
X                chsum += ch - '0';
X                ch = *(*patp)++;
X            }
X            (*patp)--;
X            ch = chsum;
X        }
X    }
X    return (ch);
X}
________This_Is_The_END________
if test `wc -l < match.c` -ne 354; then
	echo 'shar: match.c was damaged during transit (should have been 354 bytes)'
fi
fi		; : end of overwriting check
echo 'x - vmsbackup.1'
if test -f vmsbackup.1; then echo 'shar: not overwriting vmsbackup.1'; else
sed 's/^X//' << '________This_Is_The_END________' > vmsbackup.1
X.TH VMSBACKUP 1
X.SH NAME
Xvmsbackup \- read a VMS backup tape
X.SH SYNOPSIS
X.B vmsbackup
X.B \-{tx}[bcdevw][s setnumber][f tapefile]
X[ name ... ]
X.SH DESCRIPTION
X.I vmsbackup
Xreads a VMS generated backup tape, converting the files
Xto Unix format and writing the files to disc.
XThe default operation of the program is to go through an entire
Xtape, extracting every file and writing it to disc.
XThis may be modified by the following options.
X.TP 8
X.B b blocksize
XSet block size of saveset file. Default is 32256 bytes per record.
X.TP 8
X.B c
XUse complete filenames, including the version number.
XA colon and the octal version number will be appended to all filenames.
XA colon, rather than a semicolon, is used since the Unix Shell
Xuses the semicolon as the line separator.
XUsing a colon prevents the user from having to escape the semicolon
Xwhen referencing the filename.
XThis option is useful only when multiple versions of the same file
Xare on a single tape or when a file of the same name already
Xexists in the destination directory.
XThe default is to ignore version numbers.
X.TP 8
X.B d
Xuse the directory structure from VMS, the default value is off.
X.TP 8
X.B e
XProcess all filename extensions.
XSince this program is mainly intended to move source code and possibly
Xdata from a DEC system to a Unix system, the default is to ignore
Xall files whose filename extension specifies system dependent data.
XThe file types which will be ignored, unless the
X.B e
Xoption is specified, are
X.IP "" 10
Xexe     VMS executable file
X.br
Xlib     VMS object library file
X.br
Xobj     RSX object file
X.br
Xodl     RSX overlay description file
X.br
Xolb     RSX object library file
X.br
Xpmd     RSX post mortem dump file
X.br
Xstb     RSX task symbol table file
X.br
Xsys     RSX bootable system file
X.br
Xtsk     RSX executable task file
X.PP
X.TP 8
X.B f
XUse the next argument in the command line as the tape device to
Xbe used, rather than the default.
X.sp
XIf vmsbackup is compiled with the remote tape option
Xand the file name has the form
X.IR system [. user ]:/dev/???
X.I vmsbackup
Xwill use the tape drive /dev/??? on the remote system
X.IR system ,
Xvia
X.IR rsh (1),
Xand
X.IR rmt (8).
XThe optional
X.I user
Xportion of the pathname specifies the login name to use on the
Xremote system.
XIf it is not supplied, the current user's login name will be used.
XIn all the cases, the user must have the appropriate
Xpermissions on the remote machine, in order to use this facility.
XThe default is
X.I /dev/rmt8
X(drive 0, raw mode, 1600 bpi).
XThis must be a raw mode tape device.
X.TP 8
X.B s saveset
XProcess only the given saveset number.
X.TP 8
X.B t
XProduce a table of contents (a directory listing) on the standard output
Xof the files on tape.
X.TP 8
X.B v
XVerbose output.
XNormally
X.I vmsbackup
Xdoes its work silently.
XThe verbose option will cause the filenames of the files being read from
Xtape to disk to be output on the standard output.
X.TP 8
X.B w
X.I vmsbackup
Xprints the action to be taken followed by file name, then
Xwait for user confirmation. If a word beginning with `y'
Xis given, the action is done. Any other input means don't do it.
X.TP 8
X.B x
Xextract the named files from the tape.
X.TP 8
XThe optional
X.I name
Xargument specifies one or more filenames to be
Xsearched for specifically on the tape and only those files are to be processed.
XThe name may contain the usal sh(1) meta-characters *?![] \nnn.
X.SH FILES
X/dev/rmt\fIx\fP
X.SH SEE ALSO
Xrmtops(3)
X.SH BUGS
XThe filename match uses the complete VMS file names.
X
X.SH AUTHOR
XJohn Douglas Carey
X.br
XSven-Ove Westberg
________This_Is_The_END________
if test `wc -l < vmsbackup.1` -ne 127; then
	echo 'shar: vmsbackup.1 was damaged during transit (should have been 127 bytes)'
fi
fi		; : end of overwriting check
echo 'x - vmsbackup.c'
if test -f vmsbackup.c; then echo 'shar: not overwriting vmsbackup.c'; else
sed 's/^X//' << '________This_Is_The_END________' > vmsbackup.c
X/*
X *
X *  Title:
X *      Backup
X *
X *  Decription:
X *      Program to read VMS backup tape
X *
X *  Author:
X *      John Douglas CAREY.
X *      Sven-Ove Westberg    (version 3.0)
X *
X *  Net-addess:
X *      john%monu1.oz@seismo.ARPA
X *      luthcad!sow@enea.UUCP
X *
X *  History:
X *      Version 1.0 - September 1984
X *              Can only read variable length records
X *      Version 1.1
X *              Cleaned up the program from the original hack
X *              Can now read stream files
X *      Version 1.2
X *              Now convert filename from VMS to UNIX
X *                      and creates sub-directories
X *      Version 1.3
X *              Works on the Pyramid if SWAP is defined
X *      Version 1.4
X *              Reads files spanning multiple tape blocks
X *      Version 1.5
X *              Always reset reclen = 0 on file open
X *              Now output fixed length records
X *
X *      Version 2.0 - July 1985
X *              VMS Version 4.0 causes a rethink !!
X *              Now use mtio operations instead of opening and closing file
X *              Blocksize now grabed from the label
X *
X *      Version 2.1 - September 1985
X *              Handle variable length records of zero length.
X *
X *      Version 2.2 - July 1986
X *              Handle FORTRAN records of zero length.
X *              Inserted exit(0) at end of program.
X *              Distributed program in aus.sources
X *
X *      Version 2.3 - August 1986
X *              Handle FORTRAN records with record length fields
X *              at the end of a block
X *              Put debug output to a file.
X *              Distributed program in net.sources
X *
X *      Version 3.0 - December 1986
X *              Handle multiple saveset
X *              Remote tape
X *              Interactive mode
X *              File name selection with meta-characters
X *              Convert ; to : in VMS filenames
X *              Flag for usage of VMS directory structure
X *              Flag for "useless" files  eg. *.exe
X *              Flag for use VMS version in file names
X *              Flag for verbose mode
X *              Flag to list the contents of the tape
X *              Distributed to mod.sources
X *
X *      Version 4.0 - November 1988 by Timothy Stark (11TSTARK@GALLUA)
X *              Handle disk saveset
X *              Add -b option to set block size for disk saveset
X *
X *  Installation:
X *
X *      Computer Centre
X *      Monash University
X *      Wellington Road
X *      Clayton
X *      Victoria        3168
X *      AUSTRALIA
X *
X */
X#include        <stdio.h>
X#include        <ctype.h>
X
X#include        <sys/ioctl.h>
X#include        <sys/types.h>
X#ifdef REMOTE
X#include        <local/rmt.h>
X#include        <sys/stat.h>
X#endif
X#include        <sys/mtio.h>
X#include        <sys/file.h>
X
X#ifdef pyr
X#define SWAP
X#endif pyr
X
X#ifdef sun
X#define SWAP
X#endif
X
Xstruct bbh {
X        short   bbh_dol_w_size;
X        short   bbh_dol_w_opsys;
X        short   bbh_dol_w_subsys;
X        short   bbh_dol_w_applic;
X        long    bbh_dol_l_number;
X        char    bbh_dol_t_spare_1[20];
X        short   bbh_dol_w_struclev;
X        short   bbh_dol_w_volnum;
X        long    bbh_dol_l_crc;
X        long    bbh_dol_l_blocksize;
X        long    bbh_dol_l_flags;
X        char    bbh_dol_t_ssname[32];
X        short   bbh_dol_w_fid[3];
X        short   bbh_dol_w_did[3];
X        char    bbh_dol_t_filename[128];
X        char    bbh_dol_b_rtype;
X        char    bbh_dol_b_rattrib;
X        short   bbh_dol_w_rsize;
X        char    bbh_dol_b_bktsize;
X        char    bbh_dol_b_vfcsize;
X        short   bbh_dol_w_maxrec;
X        long    bbh_dol_l_filesize;
X        char    bbh_dol_t_spare_2[22];
X        short   bbh_dol_w_checksum;
X} *block_header;
X
Xstruct brh {
X        short   brh_dol_w_rsize;
X        short   brh_dol_w_rtype;
X        long    brh_dol_l_flags;
X        long    brh_dol_l_address;
X        long    brh_dol_l_spare;
X} *record_header;
X
X/* define record types */
X
X#define brh_dol_k_null  0
X#define brh_dol_k_summary       1
X#define brh_dol_k_volume        2
X#define brh_dol_k_file  3
X#define brh_dol_k_vbn   4
X#define brh_dol_k_physvol       5
X#define brh_dol_k_lbn   6
X#define brh_dol_k_fid   7
X
Xstruct bsa {
X        short   bsa_dol_w_size;
X        short   bsa_dol_w_type;
X        char    bsa_dol_t_text[1];
X} *data_item;
X
X#ifdef  STREAM
Xchar    *def_tapefile = "/dev/rts8";
X#else
Xchar    *def_tapefile = "/dev/rmt8";
X#endif
Xchar    *tapefile;
X
Xchar    filename[128];
Xint     filesize;
X
Xchar    recfmt;         /* record format */
X
X#define                 FAB_dol_C_UDF   0       /* undefined */
X#define                 FAB_dol_C_FIX   1       /* fixed-length record */
X#define                 FAB_dol_C_VAR   2       /* variable-length record */
X#define                 FAB_dol_C_VFC   3       /* variable-length with fixed-le
Xngth control record */
X#define                 FAB_dol_C_STM   4       /* RMS-11 stream record (valid o
Xnly for sequential org
X   ) */
X#define                 FAB_dol_C_STMLF 5       /* stream record delimited by LF
X (sequential org onl
X   y) */
X#define                 FAB_dol_C_STMCR 6       /* stream record delimited by CR
X (sequential org onl
X   y) */
X#define                 FAB_dol_C_MAXRFM        6       /* maximum rfm supported
X */
X
Xchar    recatt;         /* record attributes */
X
X#define                 FAB_dol_V_FTN   0       /* FORTRAN carriage control char
Xacter */
X#define                 FAB_dol_V_CR    1       /* line feed - record -carriage
Xreturn */
X#define                 FAB_dol_V_PRN   2       /* print-file carriage control *
X/
X#define                 FAB_dol_V_BLK   3       /* records don't cross block bou
Xndaries */
X
X#define FANO    20
X
X#ifdef  pyr
Xstatic struct   bsa     *file_table[FANO];
X#else
Xstruct  bsa     *file_table[FANO];
X#endif
X
XFILE    *f      = NULL;
Xint     file_count;
Xshort   reclen;
Xshort   fix;
Xshort   recsize;
Xint     vfcsize;
X
X#ifdef  NEWD
XFILE    *lf;
X#endif  NEWD
X
Xint     fd;             /* tape file descriptor */
Xint     cflag, dflag, eflag, fflag, sflag, tflag, vflag, wflag, xflag;
Xint     setnr;
Xchar    **gargv;
Xint     goptind, gargc;
X
X#define LABEL_SIZE      80
Xchar    label[LABEL_SIZE];
X
Xchar    *block;
Xint     blocksize;
X
Xstruct  mtop    op;
X
XFILE *
Xopenfile(fn)
Xchar    *fn;
X{
X        char    ufn[256];
X        char    ans[80];
X        char    *p, *q, s, *ext;
X        int     procf;
X
X        procf = 1;
X        /* copy fn to ufn and convert to lower case */
X        p = fn;
X        q = ufn;
X        while (*p) {
X                if (isupper(*p))
X                        *q = *p - 'A' + 'a';
X                else
X                        *q = *p;
X                p++;
X                q++;
X        }
X        *q = '\0';
X
X        /* convert the VMS to UNIX and make the directory path */
X        p = ufn;
X        q = ++p;
X        while (*q) {
X                if (*q == '.' || *q == ']') {
X                        s = *q;
X                        *q = '\0';
X                        if(procf && dflag) mkdir(p, 0777);
X                        *q = '/';
X                        if (s == ']')
X                                break;
X                }
X                *q++;
X        }
X        *q++;
X        if(!dflag) p=q;
X        /* strip off the version number */
X        while (*q && *q != ';') {
X                if( *q == '.') ext = q;
X                q++;
X        }
X        if (cflag) {
X                *q = ':';
X        }
X        else {
X                *q = '\0';
X        }
X        if(!eflag && procf) procf = typecmp(++ext);
X        if(procf && wflag) {
X                printf("extract %s [ny]",filename);
X                fflush(stdout);
X                gets(ans);
X                if(*ans != 'y') procf = NULL;
X        }
X        if(procf)
X                /* open the file for writing */
X                return(fopen(p, "w"));
X        else
X                return(NULL);
X}
X
Xtypecmp(str)    /* Compare the filename type in str with our list
X                   of file type to be ignored.  Return 0 if the
X                   file is to be ignored, return 1 if the
X                   file is not in our list and should not be ignored. */
Xregister char   *str;
X{
X        static char *type[] = {
X                "exe",          /* vms executable image */
X                "lib",          /* vms object library */
X                "obj",          /* rsx object file */
X                "odl",          /* rsx overlay description file */
X                "olb",          /* rsx object library */
X                "pmd",          /* rsx post mortem dump */
X                "stb",          /* rsx symbol table */
X                "sys",          /* rsx bootable system image */
X                "tsk",          /* rsx executable image */
X                "dir",
X                "upd",
X                "tlo",
X                "tlb",
X                ""              /* null string terminates list */
X        };
X        register int    i;
X
X        i = -1;
X        while (*type[++i])
X                if (strncmp(str, type[i],3) == 0)
X                        return(0);      /* found a match, file to be ignored */
X        return(1);                      /* no match found */
X}
X
Xprocess_file(buffer)
Xchar    *buffer;
X{
X        int     i, n;
X        char    *p, *q;
X        short   dsize, nblk, lnch;
X
X        int     c;
X        short   *s;
X
X        int     procf;
X
X        s = (short *) buffer;
X
X        /* check the header word */
X        if (*s != 257) {
X                printf("Snark: invalid data header\n");
X                exit(1);
X        }
X
X        c = 2;
X        for (i = 0; i < FANO; i++) {
X                file_table[i] = (struct bsa *) &buffer[c];
X#ifndef SWAP
X                dsize = file_table[i]->bsa_dol_w_size;
X#else
X                swap(&file_table[i]->bsa_dol_w_size, &dsize, sizeof(short));
X#endif
X                c += dsize + 4;
X        }
X
X        /* extract file name */
X#ifndef SWAP
X        dsize = file_table[0]->bsa_dol_w_size;
X#else
X        swap(&file_table[0]->bsa_dol_w_size, &dsize, sizeof(short));
X#endif
X        p = file_table[0]->bsa_dol_t_text;
X        q = filename;
X        for (i = 0; i < dsize; i++)
X                *q++ = *p++;
X        *q = '\0';
X
X        /* extract file's record attributes */
X#ifndef SWAP
X        dsize = file_table[5]->bsa_dol_w_size;
X#else
X        swap(&file_table[5]->bsa_dol_w_size, &dsize, sizeof(short));
X#endif
X        p = file_table[5]->bsa_dol_t_text;
X        recfmt = p[0];
X        recatt = p[1];
X#ifndef SWAP
X        bcopy(&p[2], &recsize, sizeof(short));
X#else
X        swap(&p[2], &recsize, sizeof(short));
X#endif
X        vfcsize = p[15];
X        if (vfcsize == 0)
X                vfcsize = 2;
X#ifdef  DEBUG
X        printf("recfmt = %d\n", recfmt);
X        printf("recatt = %d\n", recatt);
X        printf("reclen = %d\n", recsize);
X        printf("vfcsize = %d\n", vfcsize);
X#endif
X#ifndef SWAP
X        bcopy(&p[10], &nblk, sizeof(short));
X        bcopy(&p[12], &lnch, sizeof(short));
X#else
X        swap(&p[10], &nblk, sizeof(short));
X        swap(&p[12], &lnch, sizeof(short));
X#endif
X        filesize = (nblk-1)*512 + lnch;
X#ifdef DEBUG
X        printf("nbk = %d, lnch = %d\n", nblk, lnch);
X        printf("filesize = 0x%x\n", filesize);
X#endif
X
X        /* open the file */
X        if (f != NULL) {
X                fclose(f);
X                file_count = 0;
X                reclen = 0;
X        }
X        procf = 0;
X        if (goptind < gargc)
X                for(i=goptind; i < gargc; i++) {
X                        procf |= match(filename,gargv[i]);
X                }
X        else
X                procf = 1;
X        if (tflag && procf)
X                printf( " %-35s %8d \n",filename,filesize);
X        if (xflag && procf) {
X                /* open file */
X                f = openfile(filename);
X                if(f != NULL && vflag) printf("extracting %s\n", filename);
X        }
X}
X/*
X *
X *  process a virtual block record (file record)
X *
X */
Xprocess_vbn(buffer, rsize)
Xchar            *buffer;
Xunsigned short  rsize;
X{
X        int     c, i;
X
X        if (f == NULL) {
X                return;
X        }
X        i = 0;
X        while (file_count+i < filesize && i < rsize) {
X                switch (recfmt) {
X                case FAB_dol_C_FIX:
X                        if (reclen == 0) {
X                                reclen = recsize;
X                        }
X                        fputc(buffer[i], f);
X                        i++;
X                        reclen--;
X                        break;
X
X                case FAB_dol_C_VAR:
X                case FAB_dol_C_VFC:
X                        if (reclen == 0) {
X                                reclen = *((short *) &buffer[i]);
X#ifdef  SWAP
X                                swap(&reclen, &reclen, sizeof(short));
X#endif
X#ifdef  NEWD
X                                fprintf(lf, "---\n");
X                                fprintf(lf, "reclen = %d\n", reclen);
X                                fprintf(lf, "i = %d\n", i);
X                                fprintf(lf, "rsize = %d\n", rsize);
X#endif  NEWD
X                                fix = reclen;
X                                i += 2;
X                                if (recfmt == FAB_dol_C_VFC) {
X                                        i += vfcsize;
X                                        reclen -= vfcsize;
X                                }
X                        } else if (reclen == fix
X                                        && recatt == (1 << FAB_dol_V_FTN)) {
X                                        /****
X                                        if (buffer[i] == '0')
X                                                fputc('\n', f);
X                                        else if (buffer[i] == '1')
X                                                fputc('\f', f);
X                                        *** sow ***/
X                                        fputc(buffer[i],f); /** sow **/
X                                        i++;
X                                        reclen--;
X                        } else {
X                                fputc(buffer[i], f);
X                                i++;
X                                reclen--;
X                        }
X                        if (reclen == 0) {
X                                fputc('\n', f);
X                                if (i & 1)
X                                        i++;
X                        }
X                        break;
X
X                case FAB_dol_C_STM:
X                case FAB_dol_C_STMLF:
X                        if (reclen < 0) {
X                                printf("SCREAM\n");
X                        }
X                        if (reclen == 0) {
X                                reclen = 512;
X                        }
X                        c = buffer[i++];
X                        reclen--;
X                        if (c == '\n') {
X                                reclen = 0;
X                        }
X                        fputc(c, f);
X                        break;
X
X                case FAB_dol_C_STMCR:
X                        c = buffer[i++];
X                        if (c == '\r')
X                                fputc('\n', f);
X                        else
X                                fputc(c, f);
X                        break;
X
X                default:
X                        fclose(f);
X                        unlink(filename);
X                        fprintf(stderr, "Invalid record format = %d\n", recfmt);
X                        return;
X                }
X        }
X        file_count += i;
X}
X#ifdef  SWAP
X/*
X *
X *  do swapping for Motorola type architectures
X *
X */
Xswap(from, to, nbytes)
Xchar    *from, *to;
Xint     nbytes;
X{
X        int     i, j;
X        char    temp[100];
X
X        for (i = 0; i < nbytes; i++)
X                temp[i] = from[i];
X        for (i = 0, j = nbytes-1; i < nbytes; i++, j--)
X                to[i] = temp[j];
X}
X#endif
X/*
X *
X *  process a backup block
X *
X */
Xprocess_block(block, blocksize)
Xchar    *block;
Xint     blocksize;
X{
X
X        unsigned short  bhsize, rsize, rtype;
X        unsigned long   bsize, i;
X
X        i = 0;
X
X        /* read the backup block header */
X        block_header = (struct bbh *) &block[i];
X        i += sizeof(struct bbh);
X
X        bhsize = block_header->bbh_dol_w_size;
X        bsize = block_header->bbh_dol_l_blocksize;
X#ifdef  SWAP
X        swap(&bhsize, &bhsize, sizeof(short));
X        swap(&bsize, &bsize, sizeof(long));
X#endif
X
X        /* check the validity of the header block */
X        if (bhsize != sizeof(struct bbh)) {
X                fprintf(stderr, "Snark: Invalid header block size\n");
X                exit(1);
X        }
X        if (bsize != 0 && bsize != blocksize) {
X                fprintf(stderr, "Snark: Invalid block size\n");
X                exit(1);
X        }
X#ifdef  DEBUG
X        printf("new block: i = %d, bsize = %d\n", i, bsize);
X#endif
X
X        /* read the records */
X        while (i < bsize) {
X                /* read the backup record header */
X                record_header = (struct brh *) &block[i];
X                i += sizeof(struct brh);
X
X                rtype = record_header->brh_dol_w_rtype;
X                rsize = record_header->brh_dol_w_rsize;
X#ifdef  SWAP
X                swap(&rtype, &rtype, sizeof(short));
X                swap(&rsize, &rsize, sizeof(short));
X#endif
X#ifdef  DEBUG
X                printf("rtype = %d\n", rtype);
X                printf("rsize = %d\n", rsize);
X                printf("flags = 0x%x\n", record_header->brh_dol_l_flags);
X                printf("addr = 0x%x\n", record_header->brh_dol_l_address);
X                printf("i = %d\n", i);
X#endif
X
X                switch (rtype) {
X
X                case brh_dol_k_null:
X#ifdef  DEBUG
X                        printf("rtype = null\n");
X#endif
X                        break;
X
X                case brh_dol_k_summary:
X#ifdef  DEBUG
X                        printf("rtype = summary\n");
X#endif
X                        break;
X
X                case brh_dol_k_file:
X#ifdef  DEBUG
X                        printf("rtype = file\n");
X#endif
X                        process_file(&block[i]);
X                        break;
X
X                case brh_dol_k_vbn:
X#ifdef  DEBUG
X                        printf("rtype = vbn\n");
X#endif
X                        process_vbn(&block[i], rsize);
X                        break;
X
X                case brh_dol_k_physvol:
X#ifdef  DEBUG
X                        printf("rtype = physvol\n");
X#endif
X                        break;
X
X                case brh_dol_k_lbn:
X#ifdef  DEBUG
X                        printf("rtype = lbn\n");
X#endif
X                        break;
X
X                case brh_dol_k_fid:
X#ifdef  DEBUG
X                        printf("rtype = fid\n");
X#endif
X                        break;
X
X                default:
X                        fprintf(stderr, " Snark: invalid record type\n");
X                        fprintf(stderr, " record type = %d\n", rtype);
X                        exit(1);
X                }
X#ifdef pyr
X                i = i + rsize;
X#else
X                i += rsize;
X#endif
X        }
X}
X
Xrdhead()
X{
X        int i, nfound;
X        char name[80];
X        nfound = 1;
X        /* read the tape label - 4 records of 80 bytes */
X        while ((i = read(fd, label, LABEL_SIZE)) != 0) {
X                if (i != LABEL_SIZE) {
X                        fprintf(stderr, "Snark: bad label record\n");
X                        exit(1);
X                }
X                if (strncmp(label, "VOL1",4) == 0) {
X                        sscanf(label+4, "%14s", name);
X                        if(vflag || tflag) printf("Volume: %s\n",name);
X                }
X                if (strncmp(label, "HDR1",4) == 0) {
X                        sscanf(label+4, "%14s", name);
X                        sscanf(label+31, "%4d", &setnr);
X                }
X                /* get the block size */
X                if (strncmp(label, "HDR2", 4) == 0) {
X                        nfound = 0;
X                        sscanf(label+5, "%5d", &blocksize);
X#ifdef  DEBUG
X                        printf("blocksize = %d\n", blocksize);
X#endif
X                }
X        }
X        if((vflag || tflag) && !nfound)
X                printf("Saveset name: %s   number: %d\n",name,setnr);
X        /* get the block buffer */
X        block = (char *) malloc(blocksize);
X        if (block == (char *) 0) {
X                fprintf(stderr, "memory allocation for block failed\n");
X                exit(1);
X        }
X        return(nfound);
X}
X
Xrdtail()
X{
X        int i;
X        char name[80];
X        /* read the tape label - 4 records of 80 bytes */
X        while ((i = read(fd, label, LABEL_SIZE)) != 0) {
X                if (i != LABEL_SIZE) {
X                        fprintf(stderr, "Snark: bad label record\n");
X                        exit(1);
X                }
X                if (strncmp(label, "EOF1",4) == 0) {
X                        sscanf(label+4, "%14s", name);
X                        if(vflag || tflag)
X                                printf("End of saveset: %s\n\n\n",name);
X                }
X        }
X}
X
Xusage(progname)
Xchar    *progname;
X{
X        fprintf(stderr, "Usage:  %s -{tx}[cdevw][-b blocksize][-s setnumber][-f tapefile]\n",progname);
X}
X
X
X
X
Xmain(argc, argv)
Xint     argc;
Xchar    *argv[];
X{
X
X        char *progname;
X        int     c, i, eoffl;
X        int     selset;
X        extern int optind;
X        extern char *optarg;
X
X        progname = argv[0];
X        if(argc < 2){
X                usage(progname);
X                exit(1);
X        }
X        gargv = argv;
X        gargc = argc;
X        blocksize = 32256;
X        tapefile = def_tapefile;
X        cflag=dflag=eflag=fflag=sflag=tflag=vflag=wflag=xflag=0;
X        while((c=getopt(argc,argv,"bcdef:s:tvwx")) != EOF)
X                switch(c){
X                case 'b':
X                        sscanf(optarg,"%d",&blocksize);
X                        break;
X                case 'c':
X                        cflag++;
X                        break;
X                case 'd':
X                        dflag++;
X                        break;
X                case 'e':
X                        eflag++;
X                        break;
X                case 'f':
X                        fflag++;
X                        tapefile = optarg;
X                        break;
X                case 's':
X                        sflag++;
X                        sscanf(optarg,"%d",&selset);
X                        break;
X                case 't':
X                        tflag++;
X                        break;
X                case 'v':
X                        vflag++;
X                        break;
X                case 'w':
X                        wflag++;
X                        break;
X                case 'x':
X                        xflag++;
X                        break;
X                case '?':
X                        usage(progname);
X                        exit(1);
X                        break;
X                };
X        if(!tflag && !xflag) {
X                usage(progname);
X                exit(1);
X        }
X        goptind = optind;
X
X#ifdef  NEWD
X        /* open debug file */
X        lf = fopen("log", "w");
X        if (lf == NULL) {
X                perror("log");
X                exit(1);
X        }
X#endif
X
X        /* open the tape/disk file */
X        fd = open(tapefile, O_RDONLY);
X        if (fd < 0) {
X                perror(tapefile);
X                exit(1);
X        }
X
X        if(!fflag) {
X                /* rewind the tape */
X                op.mt_op = MTREW;
X                op.mt_count = 1;
X                i = ioctl(fd, MTIOCTOP, &op);
X                if (i < 0) {
X                        perror(tapefile);
X                        exit(1);
X                }
X                eoffl = rdhead();
X        }
X        else {
X                eoffl = 0;
X                block = (char *) malloc(blocksize);
X        }
X
X        /* read the backup tape blocks until end of tape */
X        while (!eoffl) {
X                if(sflag && setnr != selset && !fflag) {
X                        op.mt_op = MTFSF;
X                        op.mt_count = 1;
X                        i = ioctl(fd, MTIOCTOP, &op);
X                        if (i < 0) {
X                                perror(tapefile);
X                                exit(1);
X                        }
X                        i = 0;
X                }
X                else
X                        i = read(fd, block, blocksize);
X                if(i == 0 && !fflag) {
X                        rdtail();
X                        eoffl=rdhead();
X                }
X                else if(i == 0) break;
X
X                if (i != blocksize) {
X                        fprintf(stderr, "bad block read i = %d\n", i);
X                        exit(1);
X                }
X                else{
X                        eoffl = 0;
X                        process_block(block, blocksize);
X                }
X        }
X        if(vflag || tflag) printf("End of tape\n");
X
X        /* close the tape */
X        close(fd);
X
X#ifdef  NEWD
X        /* close debug file */
X        fclose(lf);
X#endif  NEWD
X
X        /* exit cleanly */
X        exit(0);
X}
________This_Is_The_END________
if test `wc -l < vmsbackup.c` -ne 863; then
	echo 'shar: vmsbackup.c was damaged during transit (should have been 863 bytes)'
fi
fi		; : end of overwriting check
echo 'x - vmsbackup.doc'
if test -f vmsbackup.doc; then echo 'shar: not overwriting vmsbackup.doc'; else
sed 's/^X//' << '________This_Is_The_END________' > vmsbackup.doc
X
X
Xvmsbackup.exe
X			To read a tape written in VMS BACKUP format on
X			a UNIX tape drive:
X
X			/usr/local/vmsbackup.exe -xvdf /dev/rmt0
X
X			This will correctly extract the contents of the tape.
X			For example, if one of the files on the tape was
X			KINNEY:[QA.BDL.68020]68020.CKT;1   this would be
X			extracted as  ./kinney/qa/bdl/68020/68020.ckt
X
X			One time I was having a problem reading a VMS BACKUP
X			tape that I wrote last year.  It would mount, without
X			telling me the label name.  When I tried to read the
X			tape using "backup/lis mub0:", VMS would complain
X			"Tape not in valid ANSI format".  The solution was
X			to use HHB's tape drive and read the VMS BACKUP tape
X			under UNIX.
X
X								  VMSBACKUP 
X
XNAME
X	vmsbackup   Read a VMS backup tape on a UNIX system.
X
X
XSYNOPSIS
Xvmsbackup -{tx}[b blocksize][cdevw][s setnumber][f tapefile] [ name ... ]
X
X
XDESCRIPTION
X
Xvmsbackup reads a VMS generated backup tape, converting the files
Xto UNIX format and writing the files to disk.  The default operation of
Xthe program is to go through an entire tape, extracting every file and
Xwriting it to disc.  This may be modified by the following options.
X  
X	-b  blocksize	Set block size of saveset file. Default is 32256
X			bytes per record.
X  
X	-c		Use complete filenames, including the version
X			number.  A colon and the octal version number
X			will be appended to all filenames.  A colon,
X			rather than a semicolon, is used since the UNIX
X			Shell uses the semicolon as the line separator.
X			Using a colon prevents the user from having to
X			escape the semicolon when referencing the filename.
X			This option is useful only when multiple versions
X			of the same file are on a single tape or when a
X			file of the same name already exists in the dest-
X			ination directory.  The default is to ignore
X			version numbers.
X  
X 
X	-d		Use the directory structure from VMS. The default
X			value is off.
X  
X 
X	-e		Process all filename extensions.  Since this
X			program is mainly intended to move source code
X			and possibly data from a DEC system to a UNIX
X			system, the default is to ignore all files whose
X			filename extension specifies system dependent
X			data.  The file types which will be ignored,
X			unless the  -e  option is specified, are
X   
X			exe     VMS executable file
X 
X			lib     VMS object library file
X 
X			obj     RSX object file
X 
X			odl     RSX overlay description file
X 
X			olb     RSX object library file
X 
X			pmd     RSX post mortem dump file
X 
X			stb     RSX task symbol table file
X 
X			sys     RSX bootable system file
X 
X			tsk     RSX executable task file
X  
X 
X	-f		Use the next argument in the command line as
X			the tape device to be used, rather than the
X			default.
X
X			If vmsbackup is compiled with the remote tape
X			option and the file name has the form  system user
X			vmsbackup will use the tape drive /dev/??? on
X			the remote system system , via rsh and rmt.  The
X			optional user portion of the pathname specifies
X			the login name to use on the remote system.  If
X			it is not supplied, the current user's login name
X			will be used.  In all the cases, the user must
X			have the appropriate permissions on the remote
X			machine, in order to use this facility.  The
X			default is  /dev/rmt8  (drive 0, raw mode, 1600
X			bpi).  This must be a raw mode tape device.
X
X  
X	-s saveset	Process only the given saveset number.
X  
X 
X	-t		Produce a table of contents (a directory listing)
X			on the standard output of the files on tape.
X  
X 
X	-v		Verbose output.  Normally vmsbackup does its work
X			silently.  The verbose option will cause the file-
X			names of the files being read from tape to disk
X			to be output on the standard output.
X  
X 
X	-w		vmsbackup prints the action to be taken followed
X			by file name, then wait for user confirmation. If
X			a word beginning with `y' is given, the action is
X			done. Any other input means don't do it.
X  
X 
X	-x		Extract the named files from the tape.  The opt-
X			ional  name  argument specifies one or more file-
X			names to be searched for specifically on the tape
X			and only those files are to be processed.  The
X			name may contain the usal sh(1) meta-characters *?![]
X
X
X
XFILES
X	/dev/rmt x 
X
X
XSEE ALSO
X	rmtops(3)
X
X
XBUGS
X	The filename match uses the complete VMS file names.
X
X
XAUTHOR
X	John Douglas Carey
X	Sven-Ove Westberg
________This_Is_The_END________
if test `wc -l < vmsbackup.doc` -ne 146; then
	echo 'shar: vmsbackup.doc was damaged during transit (should have been 146 bytes)'
fi
fi		; : end of overwriting check
exit 0
--
Cut Here+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

- Abid.


