home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
tapeutils.tar.gz
/
tapeutils.tar
/
tuurbu.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-06-11
|
15KB
|
717 lines
/*
*
* Title:
* Backup
*
* Synopsis:
* vmsbu [-f tapefile] [-t] [filename1] [filename2] ...
*
* Decription:
* Program to extract files from a VMS backup tape
*
* -f Use the next argument as the name of the tapefile instead
* of /dev/rmt0m
*
* -t List the contents of the tape. No files are extracted and
* filename1, filename2 ... are ignored.
*
* If no filenames are specified, the entire tape is retored. If one
* or more of filename1, filename2, ... are specified, only these
* files are extracted. The filenames cannot contain wildcards and
* must be appear exactly as they are on the tape. This usually means
* that filenames must be enclosed in double quotes, as the vms version
* number is preceeded by a ";".
*
* Author:
* John Douglas CAREY.
* modified - Doug Shearer Feb 87
*
* Net-addess:
* john%monu1.oz@seismo.ARPA
*
* History:
* Version 1.0 - September 1984
* Can only read variable length records
* Version 1.1
* Cleaned up the program from the original hack
* Can now read stream files
* Version 1.2
* Now convert filename from VMS to UNIX
* and creates sub-directories
* Version 1.3
* Works on the Pyramid if SWAP is defined
* Version 1.4
* Reads files spanning multiple tape blocks
* Version 1.5
* Always reset reclen = 0 on file open
* Now output fixed length records
*
* Version 2.0 - July 1985
* VMS Version 4.0 causes a rethink !!
* Now use mtio operations instead of opening and closing file
* Blocksize now grabed from the label
*
* Version 2.1 - September 1985
* Handle variable length records of zero length.
*
* Version 2.2 - July 1986
* Handle FORTRAN records of zero length.
* Inserted exit(0) at end of program.
* Distributed program in aus.sources
*
* Version 2.3 - August 1986
* Handle FORTRAN records with record length fields
* at the end of a block
* Put debug output to a file.
* Distributed program in net.sources
*
* Version ?? - Feb 1987 ... modified Doug Shearer
* add -f and -t options
* delete code to fix up VAX Fortran carriage control
*
* Version ?? - Jan 1990 ... modified Ken Rossman
* Change default tape drive (back) to /dev/rmt0.
*
* Installation:
*
* Computer Centre
* Monash University
* Wellington Road
* Clayton
* Victoria 3168
* AUSTRALIA
*
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mtio.h>
#include <sys/file.h>
#ifdef pyr
#define SWAP
#endif pyr
struct bbh {
short bbh_dol_w_size;
short bbh_dol_w_opsys;
short bbh_dol_w_subsys;
short bbh_dol_w_applic;
long bbh_dol_l_number;
char bbh_dol_t_spare_1[20];
short bbh_dol_w_struclev;
short bbh_dol_w_volnum;
long bbh_dol_l_crc;
long bbh_dol_l_blocksize;
long bbh_dol_l_flags;
char bbh_dol_t_ssname[32];
short bbh_dol_w_fid[3];
short bbh_dol_w_did[3];
char bbh_dol_t_filename[128];
char bbh_dol_b_rtype;
char bbh_dol_b_rattrib;
short bbh_dol_w_rsize;
char bbh_dol_b_bktsize;
char bbh_dol_b_vfcsize;
short bbh_dol_w_maxrec;
long bbh_dol_l_filesize;
char bbh_dol_t_spare_2[22];
short bbh_dol_w_checksum;
} *block_header;
struct brh {
short brh_dol_w_rsize;
short brh_dol_w_rtype;
long brh_dol_l_flags;
long brh_dol_l_address;
long brh_dol_l_spare;
} *record_header;
/* define record types */
#define brh_dol_k_null 0
#define brh_dol_k_summary 1
#define brh_dol_k_volume 2
#define brh_dol_k_file 3
#define brh_dol_k_vbn 4
#define brh_dol_k_physvol 5
#define brh_dol_k_lbn 6
#define brh_dol_k_fid 7
struct bsa {
short bsa_dol_w_size;
short bsa_dol_w_type;
char bsa_dol_t_text[1];
} *data_item;
#ifdef STREAM
char *tapefile = "/dev/rts8";
#else
char *tapefile = "/dev/rmt0";
#endif
char filename[128];
int filesize;
char recfmt; /* record format */
#define FAB_dol_C_UDF 0 /* undefined */
#define FAB_dol_C_FIX 1 /* fixed-length record */
#define FAB_dol_C_VAR 2 /* variable-length record */
#define FAB_dol_C_VFC 3 /* variable-length with fixed-length control record */
#define FAB_dol_C_STM 4 /* RMS-11 stream record (valid only for sequential org) */
#define FAB_dol_C_STMLF 5 /* stream record delimited by LF (sequential org only) */
#define FAB_dol_C_STMCR 6 /* stream record delimited by CR (sequential org only) */
#define FAB_dol_C_MAXRFM 6 /* maximum rfm supported */
char recatt; /* record attributes */
#define FAB_dol_V_FTN 0 /* FORTRAN carriage control character */
#define FAB_dol_V_CR 1 /* line feed - record -carriage return */
#define FAB_dol_V_PRN 2 /* print-file carriage control */
#define FAB_dol_V_BLK 3 /* records don't cross block boundaries */
#define FANO 20
#ifdef pyr
static struct bsa *file_table[FANO];
#else
struct bsa *file_table[FANO];
#endif
FILE *f = NULL;
int file_count;
short reclen;
short fix;
short recsize;
int vfcsize;
#ifdef NEWD
FILE *lf;
#endif NEWD
#define TRUE 1
#define FALSE 0
char **selected_names;
int select = FALSE;
int list = FALSE;
FILE *
openfile(fn)
char *fn;
{
char ufn[256];
char *p, *q, s;
/* copy fn to ufn and convert to lower case */
p = fn;
q = ufn;
while (*p) {
if (isupper(*p))
*q = *p - 'A' + 'a';
else
*q = *p;
p++;
q++;
}
*q = '\0';
/* convert the VMS to UNIX and make the directory path */
p = ufn;
q = ++p;
while (*q) {
if (*q == '.' || *q == ']') {
s = *q;
*q = '\0';
mkdir(p, 0755);
*q = '/';
if (s == ']')
break;
}
*q++;
}
#ifdef VERNO
/* strip off the version number */
while (*q && *q != ';')
q++;
*q = '\0';
#endif
/* open the file for writing */
return(fopen(p, "w"));
}
process_file(buffer)
char *buffer;
{
int i, n;
char *p, *q;
short dsize, nblk, lnch;
int c;
short *s;
s = (short *) buffer;
/* check the header word */
if (*s != 257) {
printf("Snark: invalid data header\n");
exit(1);
}
c = 2;
for (i = 0; i < FANO; i++) {
file_table[i] = (struct bsa *) &buffer[c];
#ifndef SWAP
dsize = file_table[i]->bsa_dol_w_size;
#else
swap(&file_table[i]->bsa_dol_w_size, &dsize, sizeof(short));
#endif
c += dsize + 4;
}
/* extract file name */
#ifndef SWAP
dsize = file_table[0]->bsa_dol_w_size;
#else
swap(&file_table[0]->bsa_dol_w_size, &dsize, sizeof(short));
#endif
p = file_table[0]->bsa_dol_t_text;
q = filename;
for (i = 0; i < dsize; i++)
*q++ = *p++;
*q = '\0';
/* extract file's record attributes */
#ifndef SWAP
dsize = file_table[5]->bsa_dol_w_size;
#else
swap(&file_table[5]->bsa_dol_w_size, &dsize, sizeof(short));
#endif
p = file_table[5]->bsa_dol_t_text;
recfmt = p[0];
recatt = p[1];
#ifndef SWAP
bcopy(&p[2], &recsize, sizeof(short));
#else
swap(&p[2], &recsize, sizeof(short));
#endif
vfcsize = p[15];
if (vfcsize == 0)
vfcsize = 2;
#ifdef DEBUG
printf("recfmt = %d\n", recfmt);
printf("recatt = %d\n", recatt);
printf("reclen = %d\n", recsize);
printf("vfcsize = %d\n", vfcsize);
#endif
#ifndef SWAP
bcopy(&p[10], &nblk, sizeof(short));
bcopy(&p[12], &lnch, sizeof(short));
#else
swap(&p[10], &nblk, sizeof(short));
swap(&p[12], &lnch, sizeof(short));
#endif
filesize = (nblk-1)*512 + lnch;
#ifdef DEBUG
printf("nbk = %d, lnch = %d\n", nblk, lnch);
printf("filesize = 0x%x\n", filesize);
#endif
/* open the file */
if (f != NULL) {
fclose(f);
file_count = 0;
reclen = 0;
}
/* this is a real HACK: */
/* if listing the tape, print file name and put file to /dev/null */
/* if selecting files and this one is not selected put file to /dev/null */
/* if " " " " " " selected print "extracted" and */
/* open the real file name */
if (list == TRUE) {
printf("%s\n", filename);
f = openfile("/dev/null");
} else if (select == FALSE |
(select == TRUE && is_it_selected(filename) == TRUE)) {
printf("extracting %s\n", filename);
f = openfile(filename);
} else {
f = openfile("/dev/null");
}
}
/*
*
* does the filename match one of the ones the user asked for ?
*
*/
is_it_selected(filename)
char *filename;
{
char **tmp;
for (tmp = selected_names; *tmp != NULL; tmp++) {
if (!strcmp(filename, *tmp))
return(1);
}
return(0);
}
/*
*
* process a virtual block record (file record)
*
*/
process_vbn(buffer, rsize)
char *buffer;
unsigned short rsize;
{
int c, i;
if (f == NULL) {
return;
}
i = 0;
while (file_count+i < filesize && i < rsize) {
switch (recfmt) {
case FAB_dol_C_FIX:
if (reclen == 0) {
reclen = recsize;
}
fputc(buffer[i], f);
i++;
reclen--;
if (recsize % 2 == 1 && reclen == 0) {
/* skip the null character padding at end of odd */
/* length record */
i++;
}
break;
case FAB_dol_C_VAR:
case FAB_dol_C_VFC:
if (reclen == 0) {
reclen = *((short *) &buffer[i]);
#ifdef SWAP
swap(&reclen, &reclen, sizeof(short));
#endif
#ifdef NEWD
fprintf(lf, "---\n");
fprintf(lf, "reclen = %d\n", reclen);
fprintf(lf, "i = %d\n", i);
fprintf(lf, "rsize = %d\n", rsize);
#endif NEWD
fix = reclen;
i += 2;
if (recfmt == FAB_dol_C_VFC) {
i += vfcsize;
reclen -= vfcsize;
}
#ifdef FIX_FORT_CARRIAGECONTROL
} else if (reclen == fix
&& recatt == (1 << FAB_dol_V_FTN)) {
if (buffer[i] == '0')
fputc('\n', f);
else if (buffer[i] == '1')
fputc('\f', f);
i++;
reclen--;
#endif FIX_FORT_CARRIAGECONTROL
} else {
fputc(buffer[i], f);
i++;
reclen--;
}
if (reclen == 0) {
fputc('\n', f);
if (i & 1)
i++;
}
break;
case FAB_dol_C_STM:
case FAB_dol_C_STMLF:
if (reclen < 0) {
printf("SCREAM\n");
}
if (reclen == 0) {
reclen = 512;
}
c = buffer[i++];
reclen--;
if (c == '\n') {
reclen = 0;
}
fputc(c, f);
break;
case FAB_dol_C_STMCR:
c = buffer[i++];
if (c == '\r')
fputc('\n', f);
else
fputc(c, f);
break;
default:
fclose(f);
unlink(filename);
fprintf(stderr, "Invalid record format = %d\n", recfmt);
return;
}
}
file_count += i;
}
#ifdef SWAP
/*
*
* do swapping for Motorola type architectures
*
*/
swap(from, to, nbytes)
char *from, *to;
int nbytes;
{
int i, j;
char temp[100];
for (i = 0; i < nbytes; i++)
temp[i] = from[i];
for (i = 0, j = nbytes-1; i < nbytes; i++, j--)
to[i] = temp[j];
}
#endif
/*
*
* process a backup block
*
*/
process_block(block, blocksize)
char *block;
int blocksize;
{
unsigned short bhsize, rsize, rtype;
unsigned long bsize, i;
i = 0;
/* read the backup block header */
block_header = (struct bbh *) &block[i];
i += sizeof(struct bbh);
bhsize = block_header->bbh_dol_w_size;
bsize = block_header->bbh_dol_l_blocksize;
#ifdef SWAP
swap(&bhsize, &bhsize, sizeof(short));
swap(&bsize, &bsize, sizeof(long));
#endif
/* check the validity of the header block */
if (bhsize != sizeof(struct bbh)) {
fprintf(stderr, "Snark: Invalid header block size\n");
exit(1);
}
if (bsize != 0 && bsize != blocksize) {
fprintf(stderr, "Snark: Invalid block size\n");
exit(1);
}
#ifdef DEBUG
printf("new block: i = %d, bsize = %d\n", i, bsize);
#endif
/* read the records */
while (i < bsize) {
/* read the backup record header */
record_header = (struct brh *) &block[i];
i += sizeof(struct brh);
rtype = record_header->brh_dol_w_rtype;
rsize = record_header->brh_dol_w_rsize;
#ifdef SWAP
swap(&rtype, &rtype, sizeof(short));
swap(&rsize, &rsize, sizeof(short));
#endif
#ifdef DEBUG
printf("rtype = %d\n", rtype);
printf("rsize = %d\n", rsize);
printf("flags = 0x%x\n", record_header->brh_dol_l_flags);
printf("addr = 0x%x\n", record_header->brh_dol_l_address);
printf("i = %d\n", i);
#endif
switch (rtype) {
case brh_dol_k_null:
#ifdef DEBUG
printf("rtype = null\n");
#endif
break;
case brh_dol_k_summary:
#ifdef DEBUG
printf("rtype = summary\n");
#endif
break;
case brh_dol_k_file:
#ifdef DEBUG
printf("rtype = file\n");
#endif
process_file(&block[i]);
break;
case brh_dol_k_vbn:
#ifdef DEBUG
printf("rtype = vbn\n");
#endif
process_vbn(&block[i], rsize);
break;
case brh_dol_k_physvol:
#ifdef DEBUG
printf("rtype = physvol\n");
#endif
break;
case brh_dol_k_lbn:
#ifdef DEBUG
printf("rtype = lbn\n");
#endif
break;
case brh_dol_k_fid:
#ifdef DEBUG
printf("rtype = fid\n");
#endif
break;
default:
fprintf(stderr, " Snark: invalid record type\n");
fprintf(stderr, " record type = %d\n", rtype);
exit(1);
}
#ifdef pyr
i = i + rsize;
#else
i += rsize;
#endif
}
}
#define LABEL_SIZE 80
main(argc, argv)
int argc;
char *argv[];
{
int fd; /* tape file descriptor */
int i;
char label[LABEL_SIZE];
char *strncpy();
char *block;
int blocksize;
struct mtop op;
#ifdef NEWD
/* open debug file */
lf = fopen("log", "w");
if (lf == NULL) {
perror("log");
exit(1);
}
#endif
for (argc--, argv++; argc > 0; argc--, argv++) {
if (!strcmp(*argv, "-f")) {
argc--, argv++;
tapefile = *argv;
} else if (!strcmp(*argv, "-t")) {
list = TRUE;
} else if (*argv == NULL) {
select = FALSE;
break;
} else {
select = TRUE;
selected_names = argv;
break;
}
}
/* open the tape file */
fd = open(tapefile, O_RDONLY);
if (fd < 0) {
fprintf(stderr,"open error\n");
perror(tapefile);
exit(1);
}
/* rewind the tape */
op.mt_op = MTREW;
op.mt_count = 1;
i = ioctl(fd, MTIOCTOP, &op);
if (i < 0) {
fprintf(stderr,"ioctl MTREW error\n");
perror(tapefile);
exit(1);
}
/* read the tape label - 4 records of 80 bytes */
while ((i = read(fd, label, LABEL_SIZE)) != 0) {
if (i != LABEL_SIZE) {
fprintf(stderr, "Snark: bad label record\n");
exit(1);
}
/* get the block size */
if (strncmp(label, "HDR2", 4) == 0) {
sscanf(label+5, "%5d", &blocksize);
#ifdef DEBUG
printf("blocksize = %d\n", blocksize);
#endif
}
}
#ifdef BOB
op.mt_op = MTFSF;
op.mt_count = 0;
i = ioctl(fd, MTIOCTOP, &op);
if ( i < 0) {
fprintf(stderr,"ioctl MTFSF error\n");
perror(tapefile);
exit(1);
}
#endif
/* get the block buffer */
block = (char *) malloc(blocksize);
if (block == (char *) 0) {
fprintf(stderr, "memory allocation for block failed\n");
exit(1);
}
/* read the backup tape blocks until end of file */
while ((i = read(fd, block, blocksize)) != 0) {
if (i != blocksize) {
fprintf(stderr, "bad block read i = %d\n", i);
exit(1);
}
process_block(block, blocksize);
}
printf("End of save set\n");
/* close the tape */
close(fd);
#ifdef NEWD
/* close debug file */
fclose(lf);
#endif NEWD
/* exit cleanly */
exit(0);
}