char *vers = "copytape version 1.2, 15 May 87"; /* copytape -- tape-to-tape copy program */ /* /* F. da Cruz, Columbia University Center for Computing Activities, May 1987 */ /* /* Parts cribbed from Jim Guyton's readtape and writetape programs, and */ /* from ansitar. If run with debug printout, output tape is slightly /* /* longer than input tape. */ /* Suggested minor improvements: check that input & output devices are */ /* really tapes. Really check that input & output tape not same device. */ /* Add some statistics. Use dynamic buffers & pointers, rather than fixed, */ /* to save space. Etc. */ /* Includes */ #include /* standard i/o */ #include /* data types needed by below */ #include /* magtape i/o */ #include /* i/o control */ /* I/O descriptors, flags, etc. */ int in, out; /* input, output tapes */ int teof; /* input tape eof flag */ int debug = 0, dv = 0; /* command line option flags */ long copyfile(); /* forward dcl of non-int function */ /* Tape stuff */ char *indef = "/dev/rmt12"; /* default input drive */ char *outdef = "/dev/rmt13"; /* default output drive */ char *intape = ""; char *outape = ""; struct mtop mtx; /* tape i/o structure for ioctl */ /* Buffer stuff */ #define BLKSIZE 30*1024 /* I/O buffer size */ #define BLOCKS 10 /* Number of buffers */ int maxblock = BLKSIZE; char buf[BLOCKS][BLKSIZE]; /* Declare buffer array */ int buflen[BLOCKS]; /* & array of data lengths per buf */ char errbuf[100]; /* Buffer for making error strings */ /* Main program */ main(argc,argv) int argc; char *argv[]; { long ct, files, bytes = 0L; int filenum = 1; char x, *xp; while (--argc > 0) { /* Parse options */ argv++; if (**argv == '-') { x = *(*argv+1); /* Option letter */ xp = *argv+1; /* Point past dash */ while (x) { /* Loop thru bundled options */ switch(x) { case 'd': /* Debugging display */ debug = 1; break; case 'f': /* From device */ if (*(xp+1)) fatal("Invalid argument bundling"); intape = *++argv; argc--; if (*intape == '-' || argc <= 0) fatal("-f argument missing"); break; case 't': /* To device */ if (*(xp+1)) fatal("Invalid argument bundling"); outape = *++argv; argc--; if (*outape == '-' || argc <= 0) fatal("-t argument missing"); break; case 'v': /* Version info */ dv = 1; break; default : usage(); } x = *++xp; /* See if options are bundled */ } } else usage(); } if (debug || dv) { /* Display version info if asked */ fprintf(stderr,"%s\n",vers); fprintf(stderr,"%d buffers, %d bytes each\n\n",BLOCKS,maxblock); } if (!*intape) intape = indef; /* Supply defaults */ if (!*outape) outape = outdef; if (strcmp(intape,"0") == 0) intape = indef; if (strcmp(intape,"1") == 0) intape = outdef; if (strcmp(outape,"0") == 0) outape = indef; if (strcmp(outape,"1") == 0) outape = outdef; if (strcmp(outape,intape) == 0) { fprintf(stderr,"You must specify two different tape drives\n"); exit(1); } if (debug) { fprintf(stderr,"input drive: %s\n",intape); fprintf(stderr,"output drive: %s\n",outape); } in = open(intape, 0); /* Open input tape */ if (in > 0) printf("Reading from tape '%s'\n", intape); else { sprintf(errbuf,"Can't open tape %s for reading",intape); fatal(errbuf); } if (rew(in) < 0) /* Rewind to load point */ fatal("Can't rewind input tape"); out = open(outape, 1); /* Open output tape */ if (out > 0) printf("Writing to tape '%s'\n", outape); else { sprintf(errbuf,"Can't open tape %s for writing",outape); fatal(errbuf); } if (rew(out) < 0) /* Rewind to load point */ fatal("Can't rewind output tape"); system("date"); /* Say when starting */ ct = files = 1; /* Initialize counters */ while (ct) { /* Copy each file on tape */ if (debug) fprintf(stderr,"\nfile %ld:", files); ct = copyfile(); /* Copy the file */ files++; /* Count the file */ bytes += ct; /* Accumulate total byte count */ } tapemark(out); /* Write final tapemark */ close(out); /* Close tape drives */ close(in); system("date"); /* When done, print messages */ printf("\nDone, copied %ld bytes in %ld file(s)\n", bytes, (files - 1)); exit(0); } long /* Copy a file from in to out */ copyfile() { /* Returns number of bytes read */ int i, blks; /* Loop control, block count */ long ct = 0; /* Character count */ teof = 0; /* Copy tape blocks till tape eof */ /* Do several buffers at a time */ while (!teof) { for (blks = i = 0; i < BLOCKS; i++) { /* Read some buffers */ if ((buflen[i] = read(in, buf[i], BLKSIZE)) < 0) fatal("I/O error reading tape"); else if (buflen[i] > 0) { blks++; /* Count this block */ if (debug) fprintf(stderr," %d:%d",i,buflen[i]); } else { /* Count of 0 means end of tape file */ if (debug) fprintf(stderr," eof"); teof = 1; /* Flag tape file eof. */ break; } } if (debug) fprintf(stderr," [%d]",blks); /* # of blocks read */ for (i = 0; i < blks; i++) { /* Write out the buffers. */ if (debug) fprintf(stderr," w%d:%d",i,buflen[i]); if (write(out, buf[i], buflen[i]) != buflen[i]) fatal("Write error"); ct += buflen[i]; /* Keep track of # of bytes written */ buflen[i] = 0; } } if (debug) fprintf(stderr," tm"); if (tapemark(out) < 0) /* Write file mark. */ fatal("Can't write tape mark"); return(ct); /* Return output byte count. */ } tapemark(tf) int tf; { /* Write a tapemark (file mark) */ mtx.mt_count = 1; mtx.mt_op = MTWEOF; return(ioctl(tf, MTIOCTOP, (char *) &mtx)); } rew(tf) int tf; { /* Rewind tape */ mtx.mt_op = MTREW; return(ioctl(tf, MTIOCTOP, (char *) &mtx)); } fatal(s) char *s; { /* Fatal error message and exit */ perror(s); /* Include last system error */ exit(1); } usage() { fprintf(stderr,"usage: copytape [-d -v -f intape -t outtape]\n"); fprintf(stderr,"-d=debug, -v=version, -f=from, -t=to\n"); fprintf(stderr,"intape default %s, outtape default %s\n",indef,outdef); fprintf(stderr,"maximum blocksize: %ld.\n",maxblock); fprintf(stderr,"number of blocks buffered: %d.\n",BLOCKS); exit(1); }