home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume10 / copytape < prev    next >
Text File  |  1987-08-06  |  14KB  |  564 lines

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v10i099:  NEW version of magtape copy program
  5. Message-ID: <791@uunet.UU.NET>
  6. Date: 7 Aug 87 11:26:06 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 553
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: sundc!hqda-ai!merlin (David S. Hayes)
  12. Posting-number: Volume 10, Issue 99
  13. Archive-name: copytape
  14.  
  15. [  This replaces what was published a few days ago.  --r$  ]
  16.  
  17. Sorry, Rich, luck is with me again.  About 2 weeks ago, someone here
  18. brought me a very odd tape, and it exposed several problems with copytape
  19. (v10 i90).  I corrected the source, but I forget that I had sent it to
  20. you.
  21.  
  22. Here's a corrected copytape.  I thought of making a diff, but that was
  23. 13k, and the whole shar was only 14k!
  24.  
  25. # This is a shell archive.  Remove anything before this line, then
  26. # unpack it by saving it in a file and typing "sh file".  (Files
  27. # unpacked will be owned by you and have default permissions.)
  28. #
  29. # This archive contains:
  30. # Makefile copytape.1 copytape.5 copytape.c
  31. #
  32. #!/bin/sh
  33. echo x - Makefile
  34. cat > "Makefile" << '//E*O*F Makefile//'
  35. MAN1 =    /usr/man/man1
  36. MAN5 =    /usr/man/man5
  37. BIN =    /usr/local/bin
  38.  
  39. CFLAGS =    -O
  40. CC =    cc $(CFLAGS)
  41.  
  42. copytape:    copytape.c
  43.     $(CC) -o copytape copytape.c
  44.  
  45. install:    copytape
  46.     install -s -m 0511 copytape ${BIN}
  47.  
  48. man:    man1 man5
  49.  
  50. man1:    ${MAN1}/copytape.1
  51.     cp copytape.1 ${MAN1}
  52.  
  53. man5:    ${MAN5}/copytape.5
  54.     cp copytape.5 ${MAN5}
  55. //E*O*F Makefile//
  56.  
  57. echo x - copytape.1
  58. cat > "copytape.1" << '//E*O*F copytape.1//'
  59. .TH COPYTAPE 1 "25 June 1986"
  60. .\"@(#)copytape.1 1.0 86/07/08 AICenter; by David S. Hayes
  61. .SH NAME
  62. copytape \- duplicate magtapes
  63. .SH SYNOPSIS
  64. .B copytape
  65. \[\-f\]
  66. \[\-t\]
  67. \[\-s\fInnn\fP\]
  68. \[\-l\fInnn\fP\]
  69. \[\-v\]
  70. .I
  71. \[input \[output\]\]
  72. .SH DESCRIPTION
  73. .LP
  74. .I copytape
  75. duplicates magtapes.  It is intended for duplication of
  76. bootable or other non-file-structured (non-tar-structured)
  77. magtapes on systems with only one tape drive.
  78. .I copytape
  79. is blissfully ignorant of tape formats.  It merely makes
  80. a bit-for-bit copy of its input.
  81. .PP
  82. In normal use,
  83. .I copytape
  84. would be run twice.  First, a boot tape is copied to an
  85. intermediate disk file.  The file is in a special format that
  86. preserves the record boundaries and tape marks.  On the second
  87. run, 
  88. .I copytape
  89. reads this file and generates a new tape.  The second step
  90. may be repeated if multiple copies are required.  The typical
  91. process would look like this:
  92. .sp
  93. .RS +.5i
  94. tutorial% copytape /dev/rmt8 tape.tmp
  95. .br
  96. tutorial% copytape tape.tmp /dev/rmt8
  97. .br
  98. tutorial% rm tape.tmp
  99. .RE
  100. .PP
  101. .I copytape
  102. copies from the standard input to the standard output, unless
  103. input and output arguments are provided.  It will automatically
  104. determine whether its input and output are physical tapes, or
  105. data files.  Data files are encoded in a special (human-readable)
  106. format.
  107. .PP
  108. Since
  109. .I copytape
  110. will automatically determine what sort of thing its input
  111. and output are, a twin-drive system can duplicate a tape in
  112. one pass.  The command would be
  113. .RS +.5i
  114. tutorial% copytape /dev/rmt8 /dev/rmt9
  115. .RE
  116. .SH OPTIONS
  117. .TP 3
  118. .RI \-s nnn
  119. Skip tape marks.  The specified number of tape marks are skipped
  120. on the input tape, before the copy begins.  By default, nothing is
  121. skipped, resulting in a copy of the complete input tape.  Multiple
  122. tar(1) and dump(1) archives on a single tape are normally
  123. separated by a single tape mark.  On ANSI or IBM labelled tapes,
  124. each file has three associated tape marks.  Count carefully.
  125. .TP 3
  126. .RI \-l nnn
  127. Limit.  Only nnn files (data followed by a tape mark), at most,
  128. are copied.  This can be used to terminate a copy early.  If the
  129. skip option is also specified, the files skipped do not count
  130. against the limit.
  131. .TP 3
  132. \-f
  133. From tape.  The input is treated as though it were a physical
  134. tape, even if it is a data file.  This option can be used
  135. to copy block-structured device files other than magtapes.
  136. .TP 3
  137. \-t
  138. To tape.  The output is treated as though it were a physical
  139. tape, even if it is a data file.  Normally, data files mark
  140. physical tape blocks with a (human\-readable) header describing
  141. the block.  If the \-t option is used when the output is
  142. actually a disk file, these headers will not be written.
  143. This will extract all the information from the tape, but
  144. .I copytape
  145. will not be able to duplicate the original tape based on
  146. the resulting data file.
  147. .TP 3
  148. \-v
  149. Verbose.
  150. .I copytape
  151. does not normally produce any output on the control terminal.
  152. The verbose option will identify the input and output files,
  153. tell whether they are physical tapes or data files, and
  154. announce the size of each block copied.  This can produce
  155. a lot of output on even relatively short tapes.  It is
  156. intended mostly for diagnostic work.
  157. .SH FILES
  158. /dev/rmt*
  159. .SH "SEE ALSO"
  160. ansitape(1), dd(1), tar(1), mtio(4), copytape(5)
  161. .SH AUTHOR
  162. David S. Hayes, Site Manager, US Army Artificial Intelligence Center.
  163. Originally developed September 1984 at Rensselaer Polytechnic Institute,
  164. Troy, New York.
  165. Revised July 1986.  This software is in the public domain.
  166. .SH BUGS
  167. .LP
  168. .I copytape
  169. treats two successive file marks as logical end-of-tape.
  170. .LP
  171. The intermediate data file can consume huge amounts of
  172. disk space.  A 2400-foot reel at 6250-bpi can burn 140 megabytes.
  173. This is not strictly speaking a bug, but users should
  174. be aware of the possibility.  Check disk space with
  175. .I df(1)
  176. before starting
  177. .IR copytape .
  178. Caveat Emptor!
  179. .LP
  180. A 256K buffer is used internally.  This limits the maximum block
  181. size of the input tape.
  182. //E*O*F copytape.1//
  183.  
  184. echo x - copytape.5
  185. cat > "copytape.5" << '//E*O*F copytape.5//'
  186. .TH COPYTAPE 5  "8 August 1986"
  187. .SH NAME
  188. copytape \- copytape intermediate data file format
  189. .SH DESCRIPTION
  190. .I copytape
  191. duplicates magtapes on single\-tape systems by making
  192. an intermediate copy of the tape in a disk file.
  193. This disk file has a special format that preserves
  194. the block boundaries and tape marks of the original
  195. physical tape.
  196. .PP
  197. Each block is preceded by a header identifying what
  198. sort of block it is.  In the case of data blocks,
  199. the length of the data is also given.  Each header is
  200. on a separate text line, followed by a newline character.
  201. .sp
  202. .TP 3
  203. CPTP:BLK \fInnnnnn\fP
  204. .ti -3
  205. \fIdata\fP\\n
  206. .sp
  207. A data block is identified by the keyword
  208. .IR BLK .
  209. The length of the block is given in a six\-character
  210. numeric field.  The field is zero\-padded on the left if
  211. less than six characters are needed.  The header is
  212. followed by a newline character.
  213. The original data follows.  The data may have any characters
  214. in it, since
  215. .I copytape
  216. uses a read(2) to extract it.
  217. The data is followed by a newline, to make the file easy
  218. to view with an editor.
  219. .TP 3
  220. CPTP:MRK
  221. A tape mark was encountered in the original tape.
  222. .TP 3
  223. CPTP:EOT
  224. When two consecutive tape marks are encountered,
  225. .I copytape
  226. treats the second as a logical end\-of\-tape.  On
  227. output, both MRK and EOT generate
  228. a physical tape mark.
  229. .I copytape
  230. stops processing after copying an EOT.
  231. .SH "SEE ALSO"
  232. mtio(4)
  233. .SH BUGS
  234. Some weird tapes may not use two consecutive tape marks
  235. as logical end\-of\-tape.
  236. //E*O*F copytape.5//
  237.  
  238. echo x - copytape.c
  239. cat > "copytape.c" << '//E*O*F copytape.c//'
  240.  
  241. /*
  242.  * COPYTAPE.C
  243.  *
  244.  * This program duplicates magnetic tapes, preserving the
  245.  * blocking structure and placement of tape marks.
  246.  *
  247.  * This program was updated at
  248.  *
  249.  *    U.S. Army Artificial Intelligence Center
  250.  *    HQDA (Attn: DACS-DMA)
  251.  *    Pentagon
  252.  *    Washington, DC  20310-0200
  253.  *
  254.  *    Phone: (202) 694-6900
  255.  *
  256.  **************************************************
  257.  *
  258.  *    THIS PROGRAM IS IN THE PUBLIC DOMAIN
  259.  *
  260.  **************************************************
  261.  *
  262.  * July 1986        David S. Hayes
  263.  *        Made data file format human-readable.
  264.  *
  265.  * April 1985        David S. Hayes
  266.  *        Original Version.
  267.  */
  268.  
  269.  
  270. #include <stdio.h>
  271. #include <sys/types.h>
  272. #include <sys/ioctl.h>
  273. #include <sys/mtio.h>
  274. #include <sys/file.h>
  275.  
  276. extern int      errno;
  277.  
  278. #define BUFLEN        262144    /* max tape block size */
  279. #define TAPE_MARK    -100    /* return record length if we read a
  280.                  * tape mark */
  281. #define END_OF_TAPE    -101    /* 2 consecutive tape marks */
  282. #define FORMAT_ERROR    -102    /* data file munged */
  283.  
  284. int             totape = 0,    /* treat destination as a tape drive */
  285.                 fromtape = 0;    /* treat source as a tape drive */
  286.  
  287. int             verbose = 0;    /* tell what we're up to */
  288.  
  289. char           *source = "stdin",
  290.                *dest = "stdout";
  291.  
  292. char            tapebuf[BUFLEN];
  293.  
  294. main(argc, argv)
  295.     int             argc;
  296.     char           *argv[];
  297. {
  298.     int             from = 0,
  299.                     to = 1;
  300.     int             len;    /* number of bytes in record */
  301.     int             skip = 0;    /* number of files to skip before
  302.                  * copying */
  303.     unsigned int    limit = 0xffffffff;
  304.     int             i;
  305.     struct mtget    status;
  306.  
  307.     for (i = 1; i < argc && argv[i][0] == '-'; i++) {
  308.     switch (argv[i][1]) {
  309.       case 's':        /* skip option */
  310.         skip = atoi(&argv[i][2]);
  311.         break;
  312.  
  313.       case 'l':
  314.         limit = atoi(&argv[i][2]);
  315.         break;
  316.  
  317.       case 'f':        /* from tape option */
  318.         fromtape = 1;
  319.         break;
  320.  
  321.       case 't':        /* to tape option */
  322.         totape = 1;
  323.         break;
  324.  
  325.       case 'v':        /* be wordy */
  326.         verbose = 1;
  327.         break;
  328.  
  329.       default:
  330.         fprintf(stderr, "usage: copytape [-f] [-t] [-lnn] [-snn] [-v] from to\n");
  331.         exit(-1);
  332.     }
  333.     }
  334.  
  335.     if (i < argc) {
  336.     from = open(argv[i], O_RDONLY);
  337.     source = argv[i];
  338.     if (from == -1) {
  339.         perror("copytape: input open failed");
  340.         exit(-1);
  341.     }
  342.     i++;;
  343.     }
  344.     if (i < argc) {
  345.     to = open(argv[i], O_WRONLY | O_CREAT | O_TRUNC, 0666);
  346.     dest = argv[i];
  347.     if (to == -1) {
  348.         perror("copytape: output open failed");
  349.         exit(-1);
  350.     }
  351.     i++;
  352.     }
  353.     if (i < argc)
  354.     perror("copytape: extra arguments ignored");
  355.  
  356.     /*
  357.      * Determine if source and/or destination is a tape device. Try to
  358.      * issue a magtape ioctl to it.  If it doesn't error, then it was a
  359.      * magtape. 
  360.      */
  361.  
  362.     errno = 0;
  363.     ioctl(from, MTIOCGET, &status);
  364.     fromtape |= errno == 0;
  365.     errno = 0;
  366.     ioctl(to, MTIOCGET, &status);
  367.     totape |= errno == 0;
  368.     errno = 0;
  369.  
  370.     if (verbose) {
  371.     fprintf(stderr, "copytape: from %s (%s)\n",
  372.         source, fromtape ? "tape" : "data");
  373.     fprintf(stderr, "          to %s (%s)\n",
  374.         dest, totape ? "tape" : "data");
  375.     }
  376.  
  377.     /*
  378.      * Skip number of files, specified by -snnn, given on the command
  379.      * line. This is used to copy second and subsequent files on the
  380.      * tape. 
  381.      */
  382.  
  383.     if (verbose && skip) {
  384.     fprintf(stderr, "copytape: skipping %d input files\n", skip);
  385.     }
  386.     for (i = 0; i < skip; i++) {
  387.     do {
  388.         len = input(from);
  389.     } while (len > 0);
  390.     if (len == FORMAT_ERROR) {
  391.         perror(stderr, "copytape: format error on skip");
  392.         exit(-1);
  393.     };
  394.     if (len == END_OF_TAPE) {
  395.         fprintf(stderr, "copytape: only %d files in input\n", i);
  396.         exit(-1);
  397.     };
  398.     };
  399.  
  400.     /*
  401.      * Do the copy. 
  402.      */
  403.  
  404.     len = 0;
  405.     while (limit && !(len == END_OF_TAPE || len == FORMAT_ERROR)) {
  406.     do {
  407.         do {
  408.         len = input(from);
  409.         if (len == FORMAT_ERROR)
  410.             perror("copytape: data format error - block ignored");
  411.         } while (len == FORMAT_ERROR);
  412.  
  413.         output(to, len);
  414.  
  415.         if (verbose) {
  416.         switch (len) {
  417.           case TAPE_MARK:
  418.             fprintf(stderr, "  copied MRK\n");
  419.             break;
  420.  
  421.           case END_OF_TAPE:
  422.             fprintf(stderr, "  copied EOT\n");
  423.             break;
  424.  
  425.           default:
  426.             fprintf(stderr, "  copied %d bytes\n", len);
  427.         };
  428.         };
  429.     } while (len > 0);
  430.     limit--;
  431.     }
  432.     exit(0);
  433. }
  434.  
  435.  
  436. /*
  437.  * Input up to 256K from a file or tape. If input file is a tape, then
  438.  * do markcount stuff.  Input record length will be supplied by the
  439.  * operating system. 
  440.  */
  441.  
  442. input(fd)
  443.     int             fd;
  444. {
  445.     static          markcount = 0;    /* number of consecutive tape
  446.                      * marks */
  447.     int             len,
  448.                     l2,
  449.                     c;
  450.     char            header[40];
  451.  
  452.     if (fromtape) {
  453.     len = read(fd, tapebuf, BUFLEN);
  454.     switch (len) {
  455.       case -1:
  456.         perror("copytape: can't read input");
  457.         return END_OF_TAPE;
  458.  
  459.       case 0:
  460.         if (++markcount == 2)
  461.         return END_OF_TAPE;
  462.         else
  463.         return TAPE_MARK;
  464.  
  465.       default:
  466.         markcount = 0;        /* reset tape mark count */
  467.         return len;
  468.     };
  469.     }
  470.     /* Input is really a data file. */
  471.     l2 = read(fd, header, 5);
  472.     if (l2 != 5 || strncmp(header, "CPTP:", 5) != 0)
  473.     return FORMAT_ERROR;
  474.  
  475.     l2 = read(fd, header, 4);
  476.     if (strncmp(header, "BLK ", 4) == 0) {
  477.     l2 = read(fd, header, 7);
  478.     if (l2 != 7)
  479.         return FORMAT_ERROR;
  480.     header[6] = '\0';
  481.     len = atoi(header);
  482.     l2 = read(fd, tapebuf, len);
  483.     if (l2 != len)
  484.         return FORMAT_ERROR;
  485.     read(fd, header, 1);    /* skip trailing newline */
  486.     } else if (strncmp(header, "MRK\n", 4) == 0)
  487.     return TAPE_MARK;
  488.     else if (strncmp(header, "EOT\n", 4) == 0)
  489.     return END_OF_TAPE;
  490.     else
  491.     return FORMAT_ERROR;
  492.  
  493.     return len;
  494. }
  495.  
  496.  
  497. /*
  498.  * Copy a buffer out to a file or tape. 
  499.  *
  500.  * If output is a tape, write the record.  A length of zero indicates that
  501.  * a tapemark should be written. 
  502.  *
  503.  * If not a tape, write len to the output file, then the buffer.  
  504.  */
  505.  
  506. output(fd, len)
  507.     int             fd,
  508.                     len;
  509. {
  510.     struct mtop     op;
  511.     char            header[20];
  512.  
  513.     if (totape && (len == TAPE_MARK || len == END_OF_TAPE)) {
  514.     op.mt_op = MTWEOF;
  515.     op.mt_count = 1;
  516.     ioctl(fd, MTIOCTOP, &op);
  517.     return;
  518.     }
  519.     if (!totape) {
  520.     switch (len) {
  521.       case TAPE_MARK:
  522.         write(fd, "CPTP:MRK\n", 9);
  523.         break;
  524.  
  525.       case END_OF_TAPE:
  526.         write(fd, "CPTP:EOT\n", 9);
  527.         break;
  528.  
  529.       case FORMAT_ERROR:
  530.         break;
  531.  
  532.       default:
  533.         sprintf(header, "CPTP:BLK %06d\n", len);
  534.         write(fd, header, strlen(header));
  535.         write(fd, tapebuf, len);
  536.         write(fd, "\n", 1);
  537.     }
  538.     } else
  539.     write(fd, tapebuf, len);
  540. }
  541. //E*O*F copytape.c//
  542.  
  543. echo Possible errors detected by \'wc\' [hopefully none]:
  544. temp=/tmp/shar$$
  545. trap "rm -f $temp; exit" 0 1 2 3 15
  546. cat > $temp <<\!!!
  547.       20      43     315 Makefile
  548.      123     661    3961 copytape.1
  549.       50     259    1472 copytape.5
  550.      301     949    6532 copytape.c
  551.      494    1912   12280 total
  552. !!!
  553. wc  Makefile copytape.1 copytape.5 copytape.c | sed 's=[^ ]*/==' | diff -b $temp -
  554. exit 0
  555. -- 
  556. David S. Hayes, The Merlin of Avalon    PhoneNet:  (202) 694-6900
  557. UUCP:  *!seismo!sundc!hqda-ai!merlin    ARPA:  merlin%hqda-ai@seismo.css.gov
  558.  
  559. -- 
  560.  
  561. Rich $alz            "Anger is an energy"
  562. Cronus Project, BBN Labs    rsalz@bbn.com
  563. Moderator, comp.sources.unix    sources@uunet.uu.net
  564.