home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / tapeutils.zip / tuurbu.c < prev    next >
C/C++ Source or Header  |  1990-06-11  |  16KB  |  717 lines

  1. /*
  2.  *
  3.  *  Title:
  4.  *    Backup
  5.  *
  6.  *  Synopsis:
  7.  *      vmsbu [-f tapefile] [-t] [filename1] [filename2] ...
  8.  *
  9.  *  Decription:
  10.  *    Program to extract files from a VMS backup tape
  11.  *
  12.  *        -f  Use the next argument as the name of the tapefile instead
  13.  *                of /dev/rmt0m
  14.  *
  15.  *        -t  List the contents of the tape.  No files are extracted and
  16.  *            filename1, filename2 ... are ignored.
  17.  *
  18.  *        If no filenames are specified, the entire tape is retored.  If one
  19.  *        or more of filename1, filename2, ... are specified, only these
  20.  *        files are extracted.  The filenames cannot contain wildcards and
  21.  *        must be appear exactly as they are on the tape.  This usually means
  22.  *        that filenames must be enclosed in double quotes, as the vms version
  23.  *        number is preceeded by a ";".
  24.  *
  25.  *  Author:
  26.  *    John Douglas CAREY.
  27.  *      modified - Doug Shearer Feb 87
  28.  *
  29.  *  Net-addess:
  30.  *    john%monu1.oz@seismo.ARPA
  31.  *
  32.  *  History:
  33.  *    Version 1.0 - September 1984
  34.  *        Can only read variable length records
  35.  *    Version 1.1
  36.  *        Cleaned up the program from the original hack
  37.  *        Can now read stream files
  38.  *    Version 1.2
  39.  *        Now convert filename from VMS to UNIX
  40.  *            and creates sub-directories
  41.  *    Version 1.3
  42.  *        Works on the Pyramid if SWAP is defined
  43.  *    Version 1.4
  44.  *        Reads files spanning multiple tape blocks
  45.  *    Version 1.5
  46.  *        Always reset reclen = 0 on file open
  47.  *        Now output fixed length records
  48.  *
  49.  *      Version 2.0 - July 1985
  50.  *        VMS Version 4.0 causes a rethink !!
  51.  *        Now use mtio operations instead of opening and closing file
  52.  *        Blocksize now grabed from the label
  53.  *
  54.  *    Version 2.1 - September 1985
  55.  *        Handle variable length records of zero length.
  56.  *
  57.  *    Version 2.2 - July 1986
  58.  *        Handle FORTRAN records of zero length.
  59.  *        Inserted exit(0) at end of program.
  60.  *        Distributed program in aus.sources
  61.  *
  62.  *    Version 2.3 - August 1986
  63.  *        Handle FORTRAN records with record length fields
  64.  *        at the end of a block
  65.  *        Put debug output to a file.
  66.  *        Distributed program in net.sources
  67.  *
  68.  *    Version ?? - Feb 1987 ...  modified Doug Shearer
  69.  *        add -f and -t options
  70.  *        delete code to fix up VAX Fortran carriage control
  71.  *
  72.  *    Version ?? - Jan 1990 ...  modified Ken Rossman
  73.  *        Change default tape drive (back) to /dev/rmt0.
  74.  *
  75.  *  Installation:
  76.  *
  77.  *    Computer Centre
  78.  *    Monash University
  79.  *    Wellington Road
  80.  *    Clayton
  81.  *    Victoria    3168
  82.  *    AUSTRALIA
  83.  *
  84.  */
  85. #include    <stdio.h>
  86. #include    <ctype.h>
  87.  
  88. #include    <sys/ioctl.h>
  89. #include    <sys/types.h>
  90. #include    <sys/mtio.h>
  91. #include    <sys/file.h>
  92.  
  93. #ifdef pyr
  94. #define SWAP
  95. #endif pyr
  96.  
  97. struct bbh {
  98.     short    bbh_dol_w_size;
  99.     short    bbh_dol_w_opsys;
  100.     short    bbh_dol_w_subsys;
  101.     short    bbh_dol_w_applic;
  102.     long    bbh_dol_l_number;
  103.     char    bbh_dol_t_spare_1[20];
  104.     short    bbh_dol_w_struclev;
  105.     short    bbh_dol_w_volnum;
  106.     long    bbh_dol_l_crc;
  107.     long    bbh_dol_l_blocksize;
  108.     long    bbh_dol_l_flags;
  109.     char    bbh_dol_t_ssname[32];
  110.     short    bbh_dol_w_fid[3];
  111.     short    bbh_dol_w_did[3];
  112.     char    bbh_dol_t_filename[128];
  113.     char    bbh_dol_b_rtype;
  114.     char    bbh_dol_b_rattrib;
  115.     short    bbh_dol_w_rsize;
  116.     char    bbh_dol_b_bktsize;
  117.     char    bbh_dol_b_vfcsize;
  118.     short    bbh_dol_w_maxrec;
  119.     long    bbh_dol_l_filesize;
  120.     char    bbh_dol_t_spare_2[22];
  121.     short    bbh_dol_w_checksum;
  122. } *block_header;
  123.  
  124. struct brh {
  125.     short    brh_dol_w_rsize;
  126.     short    brh_dol_w_rtype;
  127.     long    brh_dol_l_flags;
  128.     long    brh_dol_l_address;
  129.     long    brh_dol_l_spare;
  130. } *record_header;
  131.  
  132. /* define record types */
  133.  
  134. #define    brh_dol_k_null    0
  135. #define    brh_dol_k_summary    1
  136. #define    brh_dol_k_volume    2
  137. #define    brh_dol_k_file    3
  138. #define    brh_dol_k_vbn    4
  139. #define brh_dol_k_physvol    5
  140. #define brh_dol_k_lbn    6
  141. #define    brh_dol_k_fid    7
  142.  
  143. struct bsa {
  144.     short    bsa_dol_w_size;
  145.     short    bsa_dol_w_type;
  146.     char    bsa_dol_t_text[1];
  147. } *data_item;
  148.  
  149. #ifdef    STREAM
  150. char    *tapefile = "/dev/rts8";
  151. #else
  152. char    *tapefile = "/dev/rmt0";
  153. #endif
  154.  
  155. char    filename[128];
  156. int    filesize;
  157.  
  158. char    recfmt;        /* record format */
  159.  
  160. #define            FAB_dol_C_UDF    0    /* undefined */
  161. #define            FAB_dol_C_FIX    1    /* fixed-length record */
  162. #define            FAB_dol_C_VAR    2    /* variable-length record */
  163. #define            FAB_dol_C_VFC    3    /* variable-length with fixed-length control record */
  164. #define         FAB_dol_C_STM    4    /* RMS-11 stream record (valid only for sequential org) */
  165. #define            FAB_dol_C_STMLF    5    /* stream record delimited by LF (sequential org only) */
  166. #define         FAB_dol_C_STMCR    6    /* stream record delimited by CR (sequential org only) */
  167. #define            FAB_dol_C_MAXRFM    6    /* maximum rfm supported */
  168.  
  169. char    recatt;        /* record attributes */
  170.  
  171. #define            FAB_dol_V_FTN    0    /* FORTRAN carriage control character */
  172. #define            FAB_dol_V_CR    1    /* line feed - record -carriage return */
  173. #define            FAB_dol_V_PRN    2    /* print-file carriage control */
  174. #define            FAB_dol_V_BLK    3    /* records don't cross block boundaries */
  175.  
  176. #define    FANO    20
  177.  
  178. #ifdef    pyr
  179. static struct    bsa    *file_table[FANO];
  180. #else
  181. struct    bsa    *file_table[FANO];
  182. #endif
  183.  
  184. FILE    *f    = NULL;
  185. int    file_count;
  186. short    reclen;
  187. short    fix;
  188. short    recsize;
  189. int    vfcsize;
  190.  
  191. #ifdef    NEWD
  192. FILE    *lf;
  193. #endif    NEWD
  194.  
  195. #define TRUE    1
  196. #define FALSE   0
  197.  
  198. char **selected_names; 
  199. int  select = FALSE; 
  200. int  list = FALSE; 
  201.  
  202. FILE *
  203. openfile(fn)
  204. char    *fn;
  205. {
  206.     char    ufn[256];
  207.     char    *p, *q, s;
  208.  
  209.     /* copy fn to ufn and convert to lower case */
  210.     p = fn;
  211.     q = ufn;
  212.     while (*p) {
  213.         if (isupper(*p))
  214.             *q = *p - 'A' + 'a';
  215.         else
  216.             *q = *p;
  217.         p++;
  218.         q++;
  219.     }
  220.     *q = '\0';
  221.  
  222.     /* convert the VMS to UNIX and make the directory path */
  223.     p = ufn;
  224.     q = ++p;
  225.     while (*q) {
  226.         if (*q == '.' || *q == ']') {
  227.             s = *q;
  228.             *q = '\0';
  229.             mkdir(p, 0755);
  230.             *q = '/';
  231.             if (s == ']')
  232.                 break;
  233.         }
  234.         *q++;
  235.     }
  236. #ifdef    VERNO
  237.     /* strip off the version number */
  238.     while (*q && *q != ';')
  239.         q++;
  240.     *q = '\0';
  241. #endif
  242.     /* open the file for writing */
  243.     return(fopen(p, "w"));
  244. }
  245.  
  246. process_file(buffer)
  247. char    *buffer;
  248. {
  249.     int    i, n;
  250.     char    *p, *q;
  251.     short    dsize, nblk, lnch;
  252.  
  253.     int    c;
  254.     short    *s;
  255.  
  256.     s = (short *) buffer;
  257.  
  258.     /* check the header word */
  259.     if (*s != 257) {
  260.         printf("Snark: invalid data header\n");
  261.         exit(1);
  262.     }
  263.  
  264.     c = 2;
  265.     for (i = 0; i < FANO; i++) {
  266.         file_table[i] = (struct bsa *) &buffer[c];
  267. #ifndef    SWAP
  268.         dsize = file_table[i]->bsa_dol_w_size;
  269. #else
  270.         swap(&file_table[i]->bsa_dol_w_size, &dsize, sizeof(short));
  271. #endif
  272.         c += dsize + 4;
  273.     }
  274.  
  275.     /* extract file name */
  276. #ifndef    SWAP
  277.     dsize = file_table[0]->bsa_dol_w_size;
  278. #else
  279.     swap(&file_table[0]->bsa_dol_w_size, &dsize, sizeof(short));
  280. #endif
  281.     p = file_table[0]->bsa_dol_t_text;
  282.     q = filename;
  283.     for (i = 0; i < dsize; i++)
  284.         *q++ = *p++;
  285.     *q = '\0';
  286.  
  287.     /* extract file's record attributes */
  288. #ifndef    SWAP
  289.     dsize = file_table[5]->bsa_dol_w_size;
  290. #else
  291.     swap(&file_table[5]->bsa_dol_w_size, &dsize, sizeof(short));
  292. #endif
  293.     p = file_table[5]->bsa_dol_t_text;
  294.     recfmt = p[0];
  295.     recatt = p[1];
  296. #ifndef    SWAP
  297.     bcopy(&p[2], &recsize, sizeof(short));
  298. #else
  299.     swap(&p[2], &recsize, sizeof(short));
  300. #endif
  301.     vfcsize = p[15];
  302.     if (vfcsize == 0)
  303.         vfcsize = 2;
  304. #ifdef    DEBUG
  305.     printf("recfmt = %d\n", recfmt);
  306.     printf("recatt = %d\n", recatt);
  307.     printf("reclen = %d\n", recsize);
  308.     printf("vfcsize = %d\n", vfcsize);
  309. #endif
  310. #ifndef    SWAP
  311.     bcopy(&p[10], &nblk, sizeof(short));
  312.     bcopy(&p[12], &lnch, sizeof(short));
  313. #else
  314.     swap(&p[10], &nblk, sizeof(short));
  315.     swap(&p[12], &lnch, sizeof(short));
  316. #endif
  317.     filesize = (nblk-1)*512 + lnch;
  318. #ifdef DEBUG
  319.     printf("nbk = %d, lnch = %d\n", nblk, lnch);
  320.     printf("filesize = 0x%x\n", filesize);
  321. #endif
  322.  
  323.     /* open the file */
  324.     if (f != NULL) {
  325.         fclose(f);
  326.         file_count = 0;
  327.         reclen = 0;
  328.     }
  329.  
  330. /* this is a real HACK:                                 */
  331. /*     if listing the tape, print file name and put file to /dev/null         */
  332. /*     if selecting files and this one is not selected put file to /dev/null */
  333. /*     if     "       "    "   "    "  "  selected print "extracted" and     */
  334. /*        open the real file name                         */
  335.     if (list == TRUE) {
  336.         printf("%s\n", filename);
  337.         f = openfile("/dev/null");
  338.     } else if (select == FALSE |
  339.         (select == TRUE && is_it_selected(filename) == TRUE)) {
  340.         printf("extracting %s\n", filename);
  341.         f = openfile(filename);
  342.     } else {
  343.         f = openfile("/dev/null");
  344.     }
  345. }
  346. /*
  347.  *
  348.  *  does the filename match one of the ones the user asked for ?
  349.  *
  350.  */
  351. is_it_selected(filename)
  352. char    *filename;
  353. {
  354.     char **tmp;
  355.  
  356.     for (tmp = selected_names; *tmp != NULL; tmp++) {
  357.         if (!strcmp(filename, *tmp))
  358.             return(1);
  359.     }
  360.     return(0);
  361. }
  362. /*
  363.  *
  364.  *  process a virtual block record (file record)
  365.  *
  366.  */
  367. process_vbn(buffer, rsize)
  368. char        *buffer;
  369. unsigned short    rsize;
  370. {
  371.     int    c, i;
  372.  
  373.     if (f == NULL) {
  374.         return;
  375.     }
  376.     i = 0;
  377.     while (file_count+i < filesize && i < rsize) {
  378.         switch (recfmt) {
  379.         case FAB_dol_C_FIX:
  380.             if (reclen == 0) {
  381.                 reclen = recsize;
  382.             }
  383.             fputc(buffer[i], f);
  384.             i++;
  385.             reclen--;
  386.             if (recsize % 2 == 1 && reclen == 0) {
  387.             /* skip the null character padding at end of odd  */
  388.             /* length record                  */
  389.                 i++;
  390.             }
  391.             break;
  392.  
  393.         case FAB_dol_C_VAR:
  394.         case FAB_dol_C_VFC:
  395.             if (reclen == 0) {
  396.                 reclen = *((short *) &buffer[i]);
  397. #ifdef    SWAP
  398.                 swap(&reclen, &reclen, sizeof(short));
  399. #endif
  400. #ifdef    NEWD
  401.                 fprintf(lf, "---\n");
  402.                 fprintf(lf, "reclen = %d\n", reclen);
  403.                 fprintf(lf, "i = %d\n", i);
  404.                 fprintf(lf, "rsize = %d\n", rsize);
  405. #endif    NEWD
  406.                 fix = reclen;
  407.                 i += 2;
  408.                 if (recfmt == FAB_dol_C_VFC) {
  409.                     i += vfcsize;
  410.                     reclen -= vfcsize;
  411.                 }
  412. #ifdef    FIX_FORT_CARRIAGECONTROL
  413.             } else if (reclen == fix
  414.                     && recatt == (1 << FAB_dol_V_FTN)) {
  415.                     if (buffer[i] == '0')
  416.                         fputc('\n', f);
  417.                     else if (buffer[i] == '1')
  418.                         fputc('\f', f);
  419.                     i++;
  420.                     reclen--;
  421. #endif    FIX_FORT_CARRIAGECONTROL
  422.             } else {
  423.                 fputc(buffer[i], f);
  424.                 i++;
  425.                 reclen--;
  426.             }
  427.             if (reclen == 0) {
  428.                 fputc('\n', f);
  429.                 if (i & 1)
  430.                     i++;
  431.             }
  432.             break;
  433.  
  434.         case FAB_dol_C_STM:
  435.         case FAB_dol_C_STMLF:
  436.             if (reclen < 0) {
  437.                 printf("SCREAM\n");
  438.             }
  439.             if (reclen == 0) {
  440.                 reclen = 512;
  441.             }
  442.             c = buffer[i++];
  443.             reclen--;
  444.             if (c == '\n') {
  445.                 reclen = 0;
  446.             }
  447.             fputc(c, f);
  448.             break;
  449.  
  450.         case FAB_dol_C_STMCR:
  451.             c = buffer[i++];
  452.             if (c == '\r')
  453.                 fputc('\n', f);
  454.             else
  455.                 fputc(c, f);
  456.             break;
  457.  
  458.         default:
  459.             fclose(f);
  460.             unlink(filename);
  461.             fprintf(stderr, "Invalid record format = %d\n", recfmt);
  462.             return;
  463.         }
  464.     }
  465.     file_count += i;
  466. }
  467. #ifdef    SWAP
  468. /*
  469.  *
  470.  *  do swapping for Motorola type architectures
  471.  *
  472.  */
  473. swap(from, to, nbytes)
  474. char    *from, *to;
  475. int    nbytes;
  476. {
  477.     int    i, j;
  478.     char    temp[100];
  479.  
  480.     for (i = 0; i < nbytes; i++)
  481.         temp[i] = from[i];
  482.     for (i = 0, j = nbytes-1; i < nbytes; i++, j--)
  483.         to[i] = temp[j];
  484. }
  485. #endif
  486. /*
  487.  *
  488.  *  process a backup block
  489.  *
  490.  */
  491. process_block(block, blocksize)
  492. char    *block;
  493. int    blocksize;
  494. {
  495.  
  496.     unsigned short    bhsize, rsize, rtype;
  497.     unsigned long    bsize, i;
  498.  
  499.     i = 0;
  500.  
  501.     /* read the backup block header */
  502.     block_header = (struct bbh *) &block[i];
  503.     i += sizeof(struct bbh);
  504.  
  505.     bhsize = block_header->bbh_dol_w_size;
  506.     bsize = block_header->bbh_dol_l_blocksize;
  507. #ifdef    SWAP
  508.     swap(&bhsize, &bhsize, sizeof(short));
  509.     swap(&bsize, &bsize, sizeof(long));
  510. #endif
  511.  
  512.     /* check the validity of the header block */
  513.     if (bhsize != sizeof(struct bbh)) {
  514.         fprintf(stderr, "Snark: Invalid header block size\n");
  515.         exit(1);
  516.     }
  517.     if (bsize != 0 && bsize != blocksize) {
  518.         fprintf(stderr, "Snark: Invalid block size\n");
  519.         exit(1);
  520.     }
  521. #ifdef    DEBUG
  522.     printf("new block: i = %d, bsize = %d\n", i, bsize);
  523. #endif
  524.  
  525.     /* read the records */
  526.     while (i < bsize) {
  527.         /* read the backup record header */
  528.         record_header = (struct brh *) &block[i];
  529.         i += sizeof(struct brh);
  530.  
  531.         rtype = record_header->brh_dol_w_rtype;
  532.         rsize = record_header->brh_dol_w_rsize;
  533. #ifdef    SWAP
  534.         swap(&rtype, &rtype, sizeof(short));
  535.         swap(&rsize, &rsize, sizeof(short));
  536. #endif
  537. #ifdef    DEBUG
  538.         printf("rtype = %d\n", rtype);
  539.         printf("rsize = %d\n", rsize);
  540.         printf("flags = 0x%x\n", record_header->brh_dol_l_flags);
  541.         printf("addr = 0x%x\n", record_header->brh_dol_l_address);
  542.         printf("i = %d\n", i);
  543. #endif
  544.  
  545.         switch (rtype) {
  546.  
  547.         case brh_dol_k_null:
  548. #ifdef    DEBUG
  549.             printf("rtype = null\n");
  550. #endif
  551.             break;
  552.  
  553.         case brh_dol_k_summary:
  554. #ifdef    DEBUG
  555.             printf("rtype = summary\n");
  556. #endif
  557.             break;
  558.  
  559.         case brh_dol_k_file:
  560. #ifdef    DEBUG
  561.             printf("rtype = file\n");
  562. #endif
  563.             process_file(&block[i]);
  564.             break;
  565.  
  566.         case brh_dol_k_vbn:
  567. #ifdef    DEBUG
  568.             printf("rtype = vbn\n");
  569. #endif
  570.             process_vbn(&block[i], rsize);
  571.             break;
  572.  
  573.         case brh_dol_k_physvol:
  574. #ifdef    DEBUG
  575.             printf("rtype = physvol\n");
  576. #endif
  577.             break;
  578.  
  579.         case brh_dol_k_lbn:
  580. #ifdef    DEBUG
  581.             printf("rtype = lbn\n");
  582. #endif
  583.             break;
  584.  
  585.         case brh_dol_k_fid:
  586. #ifdef    DEBUG
  587.             printf("rtype = fid\n");
  588. #endif
  589.             break;
  590.  
  591.         default:
  592.             fprintf(stderr, " Snark: invalid record type\n");
  593.             fprintf(stderr, " record type = %d\n", rtype);
  594.             exit(1);
  595.         }
  596. #ifdef pyr
  597.         i = i + rsize;
  598. #else
  599.         i += rsize;
  600. #endif
  601.     }
  602. }
  603.  
  604. #define    LABEL_SIZE    80
  605.  
  606. main(argc, argv)
  607. int    argc;
  608. char    *argv[];
  609. {
  610.     
  611.     int    fd;        /* tape file descriptor */
  612.     int    i;
  613.  
  614.     char    label[LABEL_SIZE];
  615.         char    *strncpy();
  616.     char    *block;
  617.     int    blocksize;
  618.  
  619.     struct    mtop    op;
  620.  
  621. #ifdef    NEWD
  622.     /* open debug file */
  623.     lf = fopen("log", "w");
  624.     if (lf == NULL) {
  625.         perror("log");
  626.         exit(1);
  627.     }
  628. #endif
  629.         for (argc--, argv++; argc > 0; argc--, argv++) {
  630.                 if (!strcmp(*argv, "-f")) {
  631.                         argc--, argv++;
  632.                         tapefile = *argv;
  633.                 } else if (!strcmp(*argv, "-t")) {
  634.                         list = TRUE;
  635.                 } else if (*argv == NULL) {
  636.             select = FALSE;
  637.             break;
  638.         } else {
  639.             select = TRUE;
  640.                         selected_names = argv;
  641.                         break;
  642.                 }
  643.         }
  644.     /* open the tape file */
  645.     fd = open(tapefile, O_RDONLY);
  646.     if (fd < 0) {
  647.         fprintf(stderr,"open error\n");
  648.         perror(tapefile);
  649.         exit(1);
  650.     }
  651.  
  652.     /* rewind the tape */
  653.     op.mt_op = MTREW;
  654.     op.mt_count = 1;
  655.     i = ioctl(fd, MTIOCTOP, &op);
  656.     if (i < 0) {
  657. fprintf(stderr,"ioctl MTREW error\n");
  658.         perror(tapefile);
  659.         exit(1);
  660.     }
  661.  
  662.     /* read the tape label - 4 records of 80 bytes */
  663.     while ((i = read(fd, label, LABEL_SIZE)) != 0) {
  664.         if (i != LABEL_SIZE) {
  665.             fprintf(stderr, "Snark: bad label record\n");
  666.             exit(1);
  667.         }
  668.         /* get the block size */
  669.         if (strncmp(label, "HDR2", 4) == 0) {
  670.             sscanf(label+5, "%5d", &blocksize);
  671. #ifdef    DEBUG
  672.             printf("blocksize = %d\n", blocksize);
  673. #endif
  674.         }
  675.     }
  676. #ifdef BOB
  677.     op.mt_op = MTFSF;
  678.     op.mt_count = 0;  
  679.     i = ioctl(fd, MTIOCTOP, &op);
  680.     if ( i < 0) {
  681.         fprintf(stderr,"ioctl MTFSF error\n");
  682.         perror(tapefile);
  683.         exit(1);
  684.     }
  685. #endif
  686.  
  687.     /* get the block buffer */
  688.     block = (char *) malloc(blocksize);
  689.     if (block == (char *) 0) {
  690.         fprintf(stderr, "memory allocation for block failed\n");
  691.         exit(1);
  692.     }
  693.  
  694.     /* read the backup tape blocks until end of file */ 
  695.     while ((i = read(fd, block, blocksize)) != 0) {
  696.         if (i != blocksize) {
  697.             fprintf(stderr, "bad block read i = %d\n", i);
  698.             exit(1);
  699.         }
  700.         process_block(block, blocksize);
  701.     }
  702.     printf("End of save set\n");
  703.  
  704.     /* close the tape */
  705.     close(fd);
  706.  
  707. #ifdef    NEWD
  708.     /* close debug file */
  709.     fclose(lf);
  710. #endif    NEWD
  711.  
  712.     /* exit cleanly */
  713.     exit(0);
  714. }
  715.  
  716.  
  717.