1 #include <sys/types.h>
2 #include <sys/time.h>
3 #include <sys/mtio.h>
4 #include <sys/ioctl.h>
5 #include <sys/file.h>
6 #include <sys/stat.h>
7
8 #include <a.out.h>
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <unistd.h>
12
13 char *malloc();
14 static void ansi_rewind();
15 int wflag;
16 int xflag;
17 int tflag;
18 int cflag;
19 int vflag;
20 int dflag;
21 int fflag;
22 int totalreadfiles = 0 ;
23 int totalreadblocks = 0 ;
24 int totalreadlines = 0 ;
25 int totalreadchars = 0 ;
26 int totalwritefiles = 0 ;
27 int totalwriteblocks = 0 ;
28 int totalwritelines = 0 ;
29 int totalwritechars = 0 ;
30
main(argc,argv)31 main(argc,argv)
32 int argc;
33 char *argv[];
34 {
35 struct tm *tm;
36 long timetemp,time();
37 int year;
38 int day;
39 char *tapename;
40 char *filename;
41 char *namelist=NULL;
42 char *device = "/dev/rmt12";
43 int tape;
44 int file;
45 int filenum;
46 int argnum;
47 char line[1001];
48 char vmsname[1000];
49 char unixname[1000];
50 FILE *names;
51 int count;
52 int tmp;
53 char blockchar;
54 int blocksize=2048;
55 int recordsize=1;
56
57 char *key;
58
59 timetemp = time((long *)NULL);
60 tm = localtime(&timetemp);
61 year = tm->tm_year;
62 day = tm->tm_yday;
63 tapename = malloc(10);
64 gethostname(tapename,6);
65 tapename[7]='\0';
66
67 /* parse command line */
68 if (argc < 2)
69 usage();
70
71 argv++;
72 argc--;
73 /* loop through first argument (key) */
74 argc--;
75 for (key = *argv++; *key; key++)
76 switch(*key) {
77
78 case 'f':
79 if (*argv == NULL || argc <1) {
80 fprintf(stderr,
81 "ansitape: 'f' option requires tape name \n");
82 usage();
83 }
84 device = *argv++;
85 argc--;
86 break;
87
88 case 'n':
89 if (*argv == NULL || argc <1) {
90 fprintf(stderr,
91 "ansitape: 'n' option requires file name\n");
92 usage();
93 }
94 namelist = *argv++;
95 argc--;
96 break;
97
98 case 'l':
99 if (*argv == NULL || argc<1) {
100 fprintf(stderr,
101 "ansitape: 'l' option requires label\n");
102 usage();
103 }
104 tapename = *argv++;
105 argc--;
106 break;
107
108 case 'F':
109 if(*argv == NULL) {
110 fprintf(stderr,
111 "ansitape: 'F' options requires recordsize and blocksize specifiers.\n"
112 );
113 usage();
114 }
115 tmp = sscanf(*argv++," %d%c ",&recordsize,&blockchar);
116 argc--;
117 if(tmp<1) {
118 fprintf(stderr,"illegal recordsize: recordsize set to 80\n");
119 recordsize=80;
120 } else if(tmp>1) {
121 if(blockchar == 'b') recordsize *= 512;
122 if(blockchar == 'k') recordsize *= 1024;
123 }
124
125 if (*argv == NULL) {
126 fprintf(stderr,
127 "ansitape: 'F' option requires blocksize specifier \n");
128 usage();
129 }
130 tmp = sscanf(*argv++," %d%c ",&blocksize,&blockchar);
131 argc--;
132 if(tmp<1) {
133 fprintf(stderr,"illegal blocksize: blocksize set to 2048\n");
134 blocksize=2048;
135 } else if(tmp>1) {
136 if(blockchar == 'b') blocksize *= 512;
137 if(blockchar == 'k') blocksize *= 1024;
138 }
139 if(blocksize <18) blocksize=18;
140 if(blocksize >62*1024) blocksize=62*1024;
141 fflag++;
142 break;
143
144 case 'b':
145 if (*argv == NULL) {
146 fprintf(stderr,
147 "ansitape: 'b' option requires blocksize specifier \n");
148 usage();
149 }
150 tmp = sscanf(*argv++," %d%c ",&blocksize,&blockchar);
151 argc--;
152 if(tmp<1) {
153 fprintf(stderr,"illegal blocksize: blocksize set to 2048\n");
154 blocksize=2048;
155 } else if(tmp>1) {
156 if(blockchar == 'b') blocksize *= 512;
157 if(blockchar == 'k') blocksize *= 1024;
158 }
159 if(blocksize <18) blocksize=18;
160 if(blocksize >62*1024) blocksize=62*1024;
161 break;
162
163 case 'c':
164 cflag++;
165 wflag++;
166 break;
167
168 case 'r':
169 /*I know, this should be rflag, but I just don't like r for write*/
170 wflag++;
171 break;
172
173 case 'v':
174 vflag++;
175 break;
176
177 case 'x':
178 xflag++;
179 break;
180
181 case 't':
182 tflag++;
183 break;
184
185 case '-':
186 break;
187
188 default:
189 fprintf(stderr, "ansitape: %c: unknown option\n", *key);
190 usage();
191 }
192
193 if (!wflag && !xflag && !tflag)
194 usage();
195
196 tape = open(device,wflag?O_RDWR:O_RDONLY,NULL);
197 if(tape<0) {
198 perror(device);
199 fprintf(stderr,"tape not accessable - check if drive online and write ring present\n");
200 exit(1);
201 }
202 ansi_rewind(tape);
203 filenum=1;
204 casefix(tapename);
205
206 if(cflag) {
207 writevol(tapename,tape);
208 } else {
209 getvol(tapename,tape);
210 while(1) {
211 /* read files */
212 if( readfile(tape,argc,argv) ) break;
213 filenum++;
214 }
215 backspace(tape);
216 }
217
218 if(wflag) {
219 if(namelist) {
220 if(*namelist == '-') {
221 names = stdin;
222 } else {
223 names=fopen(namelist,"r");
224 if(names == NULL) {
225 fprintf(stderr,"unable to open namelist file - no files added to tape\n");
226 }
227 }
228 while(1) {
229 fgets(line,1000,names);
230 if(feof(names)) break;
231 count = sscanf(line,"%s %s",unixname,vmsname);
232 if(count<1) continue; /* blank line */
233 if(count==1) strcpy(vmsname,unixname);
234 casefix(vmsname);
235 if(filecheck(&file,unixname)) continue;
236 writefile(tape,file,vmsname,tapename,filenum,year,day,blocksize,
237 recordsize);
238 filenum++;
239 close(file);
240 }
241 } else {
242 for(argnum=0;argnum<argc;argnum++) {
243 filename = argv[argnum];
244 if(filecheck(&file,filename)) continue;
245 casefix(filename);
246 writefile(tape,file,filename,tapename,filenum,year,day,
247 blocksize,recordsize);
248 filenum++;
249 close(file);
250 }
251 }
252 writetm(tape);
253 writetm(tape);
254 writetm(tape);
255 writetm(tape);
256 }
257 ansi_rewind(tape);
258 close(tape);
259 if(vflag && (tflag || xflag)) {
260 fprintf(stdout," read %d files in %d blocks (%d lines, %d chars)\n",
261 totalreadfiles,totalreadblocks,totalreadlines,totalreadchars);
262 }
263 if(vflag && wflag) {
264 fprintf(stdout," wrote %d files in %d blocks (%d lines, %d chars)\n",
265 totalwritefiles,totalwriteblocks,totalwritelines,totalwritechars);
266 }
267 return(0);
268 }
usage()269 usage() {
270 fprintf(stderr,
271 "ansitape: usage: ansitape -{rxtc}[flnvb] [filename] [label] [filename] [blocksize] [files]\n");
272 exit(1);
273 }
274
writefile(tape,file,filename,tapename,filenum,year,day,blocksize,recordsize)275 writefile(tape,file,filename,tapename,filenum,year,day,blocksize,recordsize)
276 int tape;
277 int file;
278 char *filename;
279 char *tapename;
280 int filenum;
281 int year;
282 int day;
283 int blocksize;
284 int recordsize;
285
286 {
287 int blocks;
288 writehdr1(tape,filename,tapename,filenum,year,day);
289 writehdr2(tape,blocksize,recordsize);
290 writehdr3(tape);
291 writetm(tape);
292 writedata(tape,file,filename,&blocks,blocksize,recordsize);
293 writetm(tape);
294 writeeof1(tape,filename,tapename,filenum,year,day,blocks);
295 writeeof2(tape,blocksize,recordsize);
296 writeeof3(tape);
297 writetm(tape);
298 totalwritefiles++;
299 }
300
writedata(tape,file,filename,blocks,blocksize,recsize)301 writedata(tape,file,filename,blocks,blocksize,recsize)
302 int tape;
303 int file;
304 char *filename;
305 int *blocks;
306 int blocksize;
307 int recsize;
308 {
309 char *ibuf;
310 char *ibufstart;
311 char *obuf;
312 char *obufstart;
313 char *endibuf;
314 char *endobuf;
315 int got;
316 int i;
317 char *j;
318 int numchar = 0 ;
319 int numline = 0 ;
320 int numblock = 0;
321 int success;
322
323 ibufstart = ibuf = malloc((unsigned)(blocksize<4096?8200:(2*blocksize+10)));
324 obufstart = obuf = malloc((unsigned)(blocksize+10));
325 endobuf = obuf + blocksize;
326 endibuf = ibuf;
327
328
329 i=0;
330 if (!fflag) {
331 while(1) {
332 if(ibuf+i>=endibuf) { /* end of input buffer */
333 strncpy(ibufstart,ibuf,endibuf-ibuf); /* copy leftover to start */
334 ibuf = ibufstart+(endibuf-ibuf); /* point to end of valid data */
335 got = read(file,ibuf,blocksize<4096?4096:2*blocksize); /* read in a chunk */
336 endibuf = ibuf + got;
337 ibuf = ibufstart; /* point to beginning of data */
338 if(got == 0) { /* end of input */
339 if(ibuf==ibufstart){ /* no leftovers */
340 break; /* done */
341 } else {
342 ibuf[i]='\n'; /* fake extra newline */
343 }
344 }
345 }
346
347 if(obuf+i+4 > endobuf) { /* end of output buffer */
348 if(i>blocksize-4) {
349 printf("record exceeds blocksize - file truncated\n");
350 break;
351 }
352 /* filled up output record - have to fill,output,restart*/
353 for(j=obuf;j<endobuf;j++) {
354 *j = '^';
355 }
356 success = write(tape,obufstart,blocksize);
357 if(success != blocksize) {
358 perror("tape");
359 fprintf(stderr," hard write error: write aborted\n");
360 ansi_rewind(tape);
361 exit(1);
362 }
363 obuf=obufstart;
364 numchar -= i;
365 i=0;
366 numblock++;
367 continue;
368 }
369
370 if(ibuf[i] == '\n') { /* end of line */
371 obuf[0] = ((i+4)/1000) + '0';
372 obuf[1] = (((i+4)/100)%10) + '0';
373 obuf[2] = (((i+4)/10)%10) + '0';
374 obuf[3] = (((i+4)/1)%10) + '0';
375 obuf += (4+i); /* size + strlen */
376 ibuf += (1+i); /* newline + strlen */
377 i=0;
378 numline++;
379 continue; /* back to the top */
380 }
381
382 obuf[i+4]=ibuf[i];
383 numchar++;
384 i++;
385
386 }
387 /* exited - write last record and go for lunch */
388 if(obuf != obufstart) {
389 for(j=obuf;j<endobuf;j++) {
390 *j = '^';
391 }
392 success = write(tape,obufstart,blocksize);
393 if(success != blocksize) {
394 perror("tape");
395 fprintf(stderr," hard write error: write aborted\n");
396 ansi_rewind(tape);
397 exit(1);
398 }
399 numblock++;
400 }
401 } else {
402 fflush(stdout);
403 while(1) {
404 /* writing an 'F' format tape */
405 got = read(file,ibuf,recsize+1);
406 if(got == 0) {
407 /* end of input */
408 if(obuf<=obufstart) {
409 break; /* done */
410 } else {
411 /* no more data, so force the record out */
412 recsize = blocksize+1;
413 }
414 } else if(got != recsize+1) {
415 printf("short read: filled\n");
416 } else if( *(ibuf+recsize) != '\n') {
417 printf("corrupted record - write aborted\b");
418 ansi_rewind(tape);
419 exit(1);
420 }
421 if(obuf+recsize >endobuf) {
422 /*would overflow output buffer, so fill up old buffer */
423 for(j=obuf;j<endobuf;j++) {
424 *j = '^';
425 }
426 /* and write it */
427 success = write(tape,obufstart,blocksize);
428 if(success != blocksize) {
429 perror("tape");
430 fprintf(stderr," hard write error: write aborted\n");
431 ansi_rewind(tape);
432 exit(1);
433 }
434 obuf=obufstart;
435 numblock++;
436 }
437 bcopy(ibuf,obuf,recsize);
438 obuf+=got-1;
439 numline++;
440 numchar += recsize;
441 }
442 numchar -= recsize;
443 numline--;
444 }
445 free(ibufstart);
446 free(obufstart);
447 if(vflag) {
448 fprintf(stdout,"r - %s: %d lines (%d chars) in %d tape blocks\n",
449 filename,numline,numchar,numblock);
450 }
451 totalwritechars += numchar;
452 totalwritelines += numline;
453 totalwriteblocks += numblock;
454 *blocks = numblock;
455 }
456
writetm(tape)457 writetm(tape)
458 int tape;
459 {
460 struct mtop mtop;
461 mtop.mt_op = MTWEOF;
462 mtop.mt_count = 1;
463 ioctl(tape,MTIOCTOP,&mtop);
464 }
465
466 void
ansi_rewind(tape)467 static ansi_rewind(tape)
468 int tape;
469 {
470 struct mtop mtop;
471 mtop.mt_op = MTREW;
472 mtop.mt_count = 1;
473 ioctl(tape,MTIOCTOP,&mtop);
474 }
475
skipfile(tape)476 skipfile(tape)
477 int tape;
478 {
479 struct mtop mtop;
480 mtop.mt_op = MTFSF;
481 mtop.mt_count = 1;
482 ioctl(tape,MTIOCTOP,&mtop);
483 }
484
backspace(tape)485 backspace(tape)
486 int tape;
487 {
488 struct mtop mtop;
489 mtop.mt_op = MTBSF;
490 mtop.mt_count = 1;
491 ioctl(tape,MTIOCTOP,&mtop);
492 }
493
writehdr1(tape,filename,tapename,filenum,year,day)494 writehdr1(tape,filename,tapename,filenum,year,day)
495 int tape;
496 char *filename;
497 char *tapename;
498 int filenum;
499 int year;
500 int day;
501 {
502 char buf[81];
503 sprintf(buf,
504 "HDR1%-17.17s%-6.6s0001%4.4d000101 %2.2d%3.3d %2.2d%3.3d 000000DECFILE11A "
505 ,filename,tapename,filenum,year,day,year,day);
506 write(tape,buf,80);
507 }
508
writeeof1(tape,filename,tapename,filenum,year,day,blocks)509 writeeof1(tape,filename,tapename,filenum,year,day,blocks)
510 int tape;
511 char *filename;
512 char *tapename;
513 int filenum;
514 int year;
515 int day;
516 int blocks;
517 {
518 char buf[81];
519 sprintf(buf,
520 "EOF1%-17.17s%-6.6s0001%4.4d000101 %2.2d%3.3d %2.2d%3.3d %6.6dDECFILE11A "
521 ,filename,tapename,filenum,year,day,year,day,blocks);
522 write(tape,buf,80);
523 }
524
writehdr2(tape,blocksize,recordsize)525 writehdr2(tape,blocksize,recordsize)
526 int tape;
527 int blocksize;
528 int recordsize;
529 {
530 char buf[81];
531 sprintf(buf,"HDR2%c%5.5d%5.5d%35.35s00%28.28s",fflag?'F':'D',
532 blocksize,recordsize," "," ");
533 write(tape,buf,80);
534 }
535
writeeof2(tape,blocksize,recordsize)536 writeeof2(tape,blocksize,recordsize)
537 int tape;
538 int blocksize;
539 int recordsize;
540 {
541 char buf[81];
542 sprintf(buf,"EOF2%c%5.5d%5.5d%35.35s00%28.28s",fflag?'F':'D',
543 blocksize,recordsize," "," ");
544 write(tape,buf,80);
545 }
546
writehdr3(tape)547 writehdr3(tape)
548 int tape;
549 {
550 char buf[81];
551 sprintf(buf, "HDR3%76.76s"," ");
552 write(tape,buf,80);
553 }
554
writeeof3(tape)555 writeeof3(tape)
556 int tape;
557 {
558 char buf[81];
559 sprintf(buf, "EOF3%76.76s"," ");
560 write(tape,buf,80);
561 }
562
writevol(tapename,tape)563 writevol(tapename,tape)
564 int tape;
565 char *tapename;
566 {
567 char buf[81];
568 sprintf(buf,"VOL1%-6.6s %26.26sD%cC%10.10s1%28.28s3",tapename," ",'%'," "," ");
569 write(tape,buf,80);
570 if(vflag) {
571 fprintf(stdout," tape labeled %-6.6s\n",tapename);
572 }
573 }
574
getvol(tapename,tape)575 getvol(tapename,tape)
576 int tape;
577 char *tapename;
578 {
579 char buf[81];
580 read(tape,buf,80);
581 sscanf(buf,"VOL1%6s",tapename);
582 if(vflag) {
583 fprintf(stdout," tape was labeled %-6.6s\n",tapename);
584 }
585 }
586
casefix(string)587 casefix(string)
588 register char *string;
589 {
590 while(*string) {
591 if(islower(*string)) {
592 *string = toupper(*string);
593 }
594 string++;
595 }
596 }
597
598 int
readfile(tape,argc,argv)599 readfile(tape,argc,argv)
600 int tape;
601 int argc;
602 char *argv[];
603 {
604 char buf[80];
605 char mode;
606 char filename[18];
607 FILE *file;
608 int extract;
609 char *ibuf;
610 char *ibufstart;
611 char *endibuf;
612 char *fixpoint;
613 int size;
614 int numblock = 0 ;
615 int numchar = 0 ;
616 int numline = 0 ;
617 int argnum;
618 int ok;
619 int blocksize;
620 int recordsize;
621
622 if(!(read(tape,buf,80))) return(1); /* no hdr record, so second eof */
623 sscanf(buf,"HDR1%17s",filename);
624 read(tape,buf,80);
625 sscanf(buf,"HDR2%c%5d%5d",&mode,&blocksize,&recordsize);
626 blocksize = blocksize>recordsize?blocksize:recordsize;
627 skipfile(tape); /* throw away rest of header(s) - not interesting */
628 ibufstart=ibuf=malloc((unsigned)(blocksize+10));
629 endibuf=ibufstart+blocksize;
630 extract=0;
631 if(tflag || xflag) {
632 ok=0;
633 if(!argc) {
634 ok=1;
635 } else for(argnum=0;argnum<argc;argnum++) {
636 casefix(argv[argnum]);
637 if(!strcmp(filename,argv[argnum])) {
638 ok=1;
639 break;
640 }
641 }
642 if(mode == 'D') {
643 if(xflag && ok) {
644 file = fopen(filename,"w");
645 if(file == NULL) {
646 perror(filename);
647 } else {
648 extract = 1;
649 }
650 }
651 while(size=read(tape,ibufstart,blocksize)) {
652 if(size != blocksize) {
653 /*
654 * somebody's brain damaged program leaves
655 * short blocks on the tape - fill them up to size
656 * (this is work THEY should have done before writing
657 * their undersized blocks)
658 */
659 for(fixpoint=ibufstart+size;fixpoint<endibuf;fixpoint++) {
660 *fixpoint='^';
661 }
662 }
663 numblock++;
664 ibuf = ibufstart;
665 while(strncmp("^^^^",ibuf,4)) {
666 #define getsize(a) ((a[0]-'0')*1000)+((a[1]-'0')*100)+((a[2]-'0')*10)+(a[3]-'0')
667 #define bad(a) (!(isdigit(ibuf[a])))
668 if(bad(0) || bad(1) || bad(2) || bad(3)) {
669 fprintf(stderr, "error: bad record length field - file may be corrupted, skipping\n");
670 break;
671 }
672 size = getsize(ibuf);
673 if(extract) {
674 fwrite(ibuf+4,sizeof(char),size-4,file);
675 fwrite("\n",1,1,file);
676 }
677 ibuf += (size);
678 numline++;
679 numchar += (size-4);
680 if(ibuf > endibuf+1) {
681 fprintf(stderr,"error: bad tape records(s) - file may be corrupted\n");
682 break;
683 }
684 if(ibuf>endibuf-4) break;
685 }
686 }
687 if(extract) {
688 fclose(file);
689 }
690 } else if (mode == 'F') {
691 if(xflag && ok) {
692 file = fopen(filename,"w");
693 if(file == NULL) {
694 perror(filename);
695 } else {
696 extract = 1;
697 }
698 }
699 while(read(tape,ibufstart,blocksize)) {
700 numblock++;
701 ibuf = ibufstart;
702 while(ibuf+recordsize <= endibuf) {
703 if(extract) {
704 fwrite(ibuf,sizeof(char),recordsize,file);
705 fwrite("\n",1,1,file);
706 }
707 ibuf += recordsize;
708 numline++;
709 numchar += recordsize;
710 }
711 }
712 if(extract) {
713 fclose(file);
714 }
715 } else {
716 fprintf(stderr,"unknown record mode (%c) - file %s skipped\n",
717 mode,filename);
718 skipfile(tape); /* throw away actual file */
719 }
720 } else {
721 /* not interested in contents of file, so move fast */
722 skipfile(tape);
723 }
724 skipfile(tape); /* throw away eof stuff - not interesting */
725 totalreadchars += numchar;
726 totalreadlines += numline;
727 totalreadblocks += numblock;
728 totalreadfiles ++;
729 if(xflag && vflag && ok) {
730 fprintf(stdout,"x - %s: %d lines (%d chars) in %d tape blocks\n",
731 filename,numline,numchar,numblock);
732 } else if(tflag && ok) {
733 fprintf(stdout,"t - %s: %d lines (%d chars) in %d tape blocks\n",
734 filename,numline,numchar,numblock);
735 }
736 free(ibufstart);
737 return(0);
738 }
739
filecheck(file,name)740 filecheck(file,name)
741 int *file;
742 char *name;
743
744 {
745
746 struct stat buf;
747 struct exec sample;
748
749 stat(name,&buf);
750 if ((buf.st_mode & S_IFDIR)==S_IFDIR) {
751 fprintf(stderr,"%s: directory - skipped\n",name);
752 return(1);
753 }
754 if ((buf.st_mode & S_IFCHR)==S_IFCHR) {
755 fprintf(stderr,"%s: character device - skipped\n",name);
756 return(1);
757 }
758 if ((buf.st_mode & S_IFBLK)==S_IFBLK) {
759 fprintf(stderr,"%s: block device - skipped\n",name);
760 return(1);
761 }
762 if ((buf.st_mode & S_IFLNK)==S_IFLNK) {
763 fprintf(stderr,"%s: symbolic link - skipped\n",name);
764 return(1);
765 }
766 if ((buf.st_mode & S_IFSOCK)==S_IFSOCK) {
767 fprintf(stderr,"%s: socket - skipped\n",name);
768 return(1);
769 }
770 *file = open(name,O_RDONLY,NULL);
771 if(*file <0) {
772 perror(name);
773 return(1);
774 }
775 if(read(*file,&sample,sizeof(struct exec))>= sizeof(struct exec)) {
776 if(!(N_BADMAG(sample))) {
777 /* executable */
778 /* the format requires either fixed blocked records,
779 * or variable format records with each record remaining
780 * entirely within a tape block - this limits the
781 * distance between \n's to 2044 bytes, something
782 * which is VERY rarely true of executables, so
783 * we don't even try with them....
784 */
785 close(*file);
786 fprintf(stderr,"%s: executable - skipped\n",name);
787 return(1);
788 }
789 }
790 /* either couldn't read sizeof(struct exec) or wasn't executable */
791 /* so we assume it is a reasonable file until proven otherwise */
792 lseek(*file,0l,0);
793 return(0);
794 }
795