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 #include <a.out.h> 8 #include <stdio.h> 9 #include <ctype.h> 10 11 char *malloc(); 12 void rewind(); 13 int wflag; 14 int xflag; 15 int tflag; 16 int cflag; 17 int vflag; 18 int dflag; 19 int fflag; 20 int totalreadfiles = 0 ; 21 int totalreadblocks = 0 ; 22 int totalreadlines = 0 ; 23 int totalreadchars = 0 ; 24 int totalwritefiles = 0 ; 25 int totalwriteblocks = 0 ; 26 int totalwritelines = 0 ; 27 int totalwritechars = 0 ; 28 29 main(argc,argv) 30 int argc; 31 char *argv[]; 32 { 33 struct tm *tm; 34 long timetemp; 35 int year; 36 int day; 37 char *tapename; 38 char *filename; 39 char *namelist=NULL; 40 char *device = "/dev/rmt12"; 41 int tape; 42 int file; 43 int filenum; 44 int argnum; 45 char line[1001]; 46 char vmsname[1000]; 47 char unixname[1000]; 48 FILE *names; 49 int count; 50 int tmp; 51 char blockchar; 52 int blocksize=2048; 53 int recordsize=1; 54 55 char *key; 56 57 timetemp = time(0); 58 tm = localtime(&timetemp); 59 year = tm->tm_year; 60 day = tm->tm_yday; 61 tapename = malloc(10); 62 gethostname(tapename,6); 63 tapename[7]='\0'; 64 65 /* parse command line */ 66 if (argc < 2) 67 usage(); 68 69 argv++; 70 argc--; 71 /* loop through first argument (key) */ 72 argc--; 73 for (key = *argv++; *key; key++) 74 switch(*key) { 75 76 case 'f': 77 if (*argv == NULL || argc <1) { 78 fprintf(stderr, 79 "ansitape: 'f' option requires tape name \n"); 80 usage(); 81 } 82 device = *argv++; 83 argc--; 84 break; 85 86 case 'n': 87 if (*argv == NULL || argc <1) { 88 fprintf(stderr, 89 "ansitape: 'n' option requires file name\n"); 90 usage(); 91 } 92 namelist = *argv++; 93 argc--; 94 break; 95 96 case 'l': 97 if (*argv == NULL || argc<1) { 98 fprintf(stderr, 99 "ansitape: 'l' option requires label\n"); 100 usage(); 101 } 102 tapename = *argv++; 103 argc--; 104 break; 105 106 case 'F': 107 if(*argv == NULL) { 108 fprintf(stderr, 109 "ansitape: 'F' options requires recordsize and blocksize specifiers.\n" 110 ); 111 usage(); 112 } 113 tmp = sscanf(*argv++," %d%c ",&recordsize,&blockchar); 114 argc--; 115 if(tmp<1) { 116 fprintf(stderr,"illegal recordsize: recordsize set to 80\n"); 117 recordsize=80; 118 } else if(tmp>1) { 119 if(blockchar == 'b') recordsize *= 512; 120 if(blockchar == 'k') recordsize *= 1024; 121 } 122 123 if (*argv == NULL) { 124 fprintf(stderr, 125 "ansitape: 'F' option requires blocksize specifier \n"); 126 usage(); 127 } 128 tmp = sscanf(*argv++," %d%c ",&blocksize,&blockchar); 129 argc--; 130 if(tmp<1) { 131 fprintf(stderr,"illegal blocksize: blocksize set to 2048\n"); 132 blocksize=2048; 133 } else if(tmp>1) { 134 if(blockchar == 'b') blocksize *= 512; 135 if(blockchar == 'k') blocksize *= 1024; 136 } 137 if(blocksize <18) blocksize=18; 138 if(blocksize >62*1024) blocksize=62*1024; 139 fflag++; 140 break; 141 142 case 'b': 143 if (*argv == NULL) { 144 fprintf(stderr, 145 "ansitape: 'b' option requires blocksize specifier \n"); 146 usage(); 147 } 148 tmp = sscanf(*argv++," %d%c ",&blocksize,&blockchar); 149 argc--; 150 if(tmp<1) { 151 fprintf(stderr,"illegal blocksize: blocksize set to 2048\n"); 152 blocksize=2048; 153 } else if(tmp>1) { 154 if(blockchar == 'b') blocksize *= 512; 155 if(blockchar == 'k') blocksize *= 1024; 156 } 157 if(blocksize <18) blocksize=18; 158 if(blocksize >62*1024) blocksize=62*1024; 159 break; 160 161 case 'c': 162 cflag++; 163 wflag++; 164 break; 165 166 case 'r': 167 /*I know, this should be rflag, but I just don't like r for write*/ 168 wflag++; 169 break; 170 171 case 'v': 172 vflag++; 173 break; 174 175 case 'x': 176 xflag++; 177 break; 178 179 case 't': 180 tflag++; 181 break; 182 183 case '-': 184 break; 185 186 default: 187 fprintf(stderr, "ansitape: %c: unknown option\n", *key); 188 usage(); 189 } 190 191 if (!wflag && !xflag && !tflag) 192 usage(); 193 194 tape = open(device,wflag?O_RDWR:O_RDONLY,NULL); 195 if(tape<0) { 196 perror(device); 197 printf(stderr,"tape not accessable - check if drive online and write ring present\n"); 198 exit(1); 199 } 200 rewind(tape); 201 filenum=1; 202 casefix(tapename); 203 204 if(cflag) { 205 writevol(tapename,tape); 206 } else { 207 getvol(tapename,tape); 208 while(1) { 209 /* read files */ 210 if( readfile(tape,argc,argv) ) break; 211 filenum++; 212 } 213 backspace(tape); 214 } 215 216 if(wflag) { 217 if(namelist) { 218 if(*namelist == '-') { 219 names = stdin; 220 } else { 221 names=fopen(namelist,"r"); 222 if(names == NULL) { 223 fprintf(stderr,"unable to open namelist file - no files added to tape\n"); 224 } 225 } 226 while(1) { 227 fgets(line,1000,names); 228 if(feof(names)) break; 229 count = sscanf(line,"%s %s",unixname,vmsname); 230 if(count<1) continue; /* blank line */ 231 if(count==1) strcpy(vmsname,unixname); 232 casefix(vmsname); 233 if(filecheck(&file,unixname)) continue; 234 writefile(tape,file,vmsname,tapename,filenum,year,day,blocksize, 235 recordsize); 236 filenum++; 237 close(file); 238 } 239 } else { 240 for(argnum=0;argnum<argc;argnum++) { 241 filename = argv[argnum]; 242 if(filecheck(&file,filename)) continue; 243 casefix(filename); 244 writefile(tape,file,filename,tapename,filenum,year,day, 245 blocksize,recordsize); 246 filenum++; 247 close(file); 248 } 249 } 250 writetm(tape); 251 writetm(tape); 252 writetm(tape); 253 writetm(tape); 254 } 255 rewind(tape); 256 close(tape); 257 if(vflag && (tflag || xflag)) { 258 fprintf(stdout," read %d files in %d blocks (%d lines, %d chars)\n", 259 totalreadfiles,totalreadblocks,totalreadlines,totalreadchars); 260 } 261 if(vflag && wflag) { 262 fprintf(stdout," wrote %d files in %d blocks (%d lines, %d chars)\n", 263 totalwritefiles,totalwriteblocks,totalwritelines,totalwritechars); 264 } 265 } 266 usage() { 267 fprintf(stderr, 268 "ansitape: usage: ansitape -{rxtc}[flnvb] [filename] [label] [filename] [blocksize] [files]\n"); 269 exit(); 270 } 271 272 writefile(tape,file,filename,tapename,filenum,year,day,blocksize,recordsize) 273 int tape; 274 int file; 275 char *filename; 276 char *tapename; 277 int filenum; 278 int year; 279 int day; 280 int blocksize; 281 int recordsize; 282 283 { 284 int blocks; 285 writehdr1(tape,filename,tapename,filenum,year,day); 286 writehdr2(tape,blocksize,recordsize); 287 writehdr3(tape); 288 writetm(tape); 289 writedata(tape,file,filename,&blocks,blocksize,recordsize); 290 writetm(tape); 291 writeeof1(tape,filename,tapename,filenum,year,day,blocks); 292 writeeof2(tape,blocksize,recordsize); 293 writeeof3(tape); 294 writetm(tape); 295 totalwritefiles++; 296 } 297 298 writedata(tape,file,filename,blocks,blocksize,recsize) 299 int tape; 300 int file; 301 char *filename; 302 int *blocks; 303 int blocksize; 304 int recsize; 305 { 306 char *ibuf; 307 char *ibufstart; 308 char *obuf; 309 char *obufstart; 310 char sizebuf[5]; 311 char *endibuf; 312 char *endobuf; 313 int got; 314 int i; 315 char *j; 316 int numchar = 0 ; 317 int numline = 0 ; 318 int numblock = 0; 319 int success; 320 321 ibufstart = ibuf = malloc(blocksize<4096?8200:(2*blocksize+10)); 322 obufstart = obuf = malloc(blocksize+10); 323 endobuf = obuf + blocksize; 324 endibuf = ibuf; 325 326 327 i=0; 328 if (!fflag) { 329 while(1) { 330 if(ibuf+i>=endibuf) { /* end of input buffer */ 331 strncpy(ibufstart,ibuf,endibuf-ibuf); /* copy leftover to start */ 332 ibuf = ibufstart+(endibuf-ibuf); /* point to end of valid data */ 333 got = read(file,ibuf,blocksize<4096?4096:2*blocksize); /* read in a chunk */ 334 endibuf = ibuf + got; 335 ibuf = ibufstart; /* point to beginning of data */ 336 if(got == 0) { /* end of input */ 337 if(ibuf==ibufstart){ /* no leftovers */ 338 break; /* done */ 339 } else { 340 ibuf[i]='\n'; /* fake extra newline */ 341 } 342 } 343 } 344 345 if(obuf+i+4 > endobuf) { /* end of output buffer */ 346 if(i>blocksize-4) { 347 printf("record exceeds blocksize - file truncated\n"); 348 break; 349 } 350 /* filled up output record - have to fill,output,restart*/ 351 for(j=obuf;j<endobuf;j++) { 352 *j = '^'; 353 } 354 success = write(tape,obufstart,blocksize); 355 if(success != blocksize) { 356 perror("tape"); 357 fprintf(stderr," hard write error: write aborted\n"); 358 rewind(tape); 359 exit(1); 360 } 361 obuf=obufstart; 362 numchar -= i; 363 i=0; 364 numblock++; 365 continue; 366 } 367 368 if(ibuf[i] == '\n') { /* end of line */ 369 /*sprintf(sizebuf,"%4.4d",i+4); /* make length string */ 370 /*strncpy(obuf,sizebuf,4); /* put in length field */ 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 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 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 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 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 467 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 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 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 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 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 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 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 547 writehdr3(tape) 548 int tape; 549 { 550 char buf[81]; 551 sprintf(buf, "HDR3%76.76s"," "); 552 write(tape,buf,80); 553 } 554 555 writeeof3(tape) 556 int tape; 557 { 558 char buf[81]; 559 sprintf(buf, "EOF3%76.76s"," "); 560 write(tape,buf,80); 561 } 562 563 writevol(tapename,tape) 564 int tape; 565 char *tapename; 566 { 567 char buf[81]; 568 sprintf(buf,"VOL1%-6.6s %26.26sD%56810.10s1%28.28s3",tapename," "," "," "); 569 write(tape,buf,80); 570 if(vflag) { 571 fprintf(stdout," tape labeled %-6.6s\n",tapename); 572 } 573 } 574 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 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 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 i; 614 int size; 615 int numblock = 0 ; 616 int numchar = 0 ; 617 int numline = 0 ; 618 int argnum; 619 int ok; 620 int blocksize; 621 int recordsize; 622 int writeblock; 623 624 if(!(read(tape,buf,80))) return(1); /* no hdr record, so second eof */ 625 sscanf(buf,"HDR1%17s",filename); 626 read(tape,buf,80); 627 sscanf(buf,"HDR2%c%5d%5d",&mode,&blocksize,&recordsize); 628 blocksize = blocksize>recordsize?blocksize:recordsize; 629 skipfile(tape); /* throw away rest of header(s) - not interesting */ 630 ibufstart=ibuf=malloc(blocksize+10); 631 endibuf=ibufstart+blocksize; 632 extract=0; 633 if(tflag || xflag) { 634 ok=0; 635 if(!argc) { 636 ok=1; 637 } else for(argnum=0;argnum<argc;argnum++) { 638 casefix(argv[argnum]); 639 if(!strcmp(filename,argv[argnum])) { 640 ok=1; 641 break; 642 } 643 } 644 if(mode == 'D') { 645 if(xflag && ok) { 646 file = fopen(filename,"w"); 647 if(file == NULL) { 648 perror(filename); 649 } else { 650 extract = 1; 651 } 652 } 653 while(size=read(tape,ibufstart,blocksize)) { 654 if(size != blocksize) { 655 /* 656 * somebody's brain damaged program leaves 657 * short blocks on the tape - fill them up to size 658 * (this is work THEY should have done before writing 659 * their undersized blocks) 660 */ 661 for(fixpoint=ibufstart+size;fixpoint<endibuf;fixpoint++) { 662 *fixpoint='^'; 663 } 664 } 665 numblock++; 666 ibuf = ibufstart; 667 while(strncmp("^^^^",ibuf,4)) { 668 #define getsize(a) ((a[0]-'0')*1000)+((a[1]-'0')*100)+((a[2]-'0')*10)+(a[3]-'0') 669 #define bad(a) (!(isdigit(ibuf[a]))) 670 if(bad(0) || bad(1) || bad(2) || bad(3)) { 671 fprintf(stderr, "error: bad record length field - file may be corrupted, skipping\n"); 672 break; 673 } 674 size = getsize(ibuf); 675 if(extract) { 676 fwrite(ibuf+4,sizeof(char),size-4,file); 677 fwrite("\n",1,1,file); 678 } 679 ibuf += (size); 680 numline++; 681 numchar += (size-4); 682 if(ibuf > endibuf+1) { 683 fprintf(stderr,"error: bad tape records(s) - file may be corrupted\n"); 684 break; 685 } 686 if(ibuf>endibuf-4) break; 687 } 688 } 689 if(extract) { 690 fclose(file); 691 } 692 } else if (mode == 'F') { 693 if(xflag && ok) { 694 file = fopen(filename,"w"); 695 if(file == NULL) { 696 perror(filename); 697 } else { 698 extract = 1; 699 } 700 } 701 while(read(tape,ibufstart,blocksize)) { 702 numblock++; 703 ibuf = ibufstart; 704 while(ibuf+recordsize <= endibuf) { 705 if(extract) { 706 fwrite(ibuf,sizeof(char),recordsize,file); 707 fwrite("\n",1,1,file); 708 } 709 ibuf += recordsize; 710 numline++; 711 numchar += recordsize; 712 } 713 } 714 if(extract) { 715 fclose(file); 716 } 717 } else { 718 fprintf(stderr,"unknown record mode (%c) - file %s skipped\n", 719 mode,filename); 720 skipfile(tape); /* throw away actual file */ 721 } 722 } else { 723 /* not interested in contents of file, so move fast */ 724 skipfile(tape); 725 } 726 skipfile(tape); /* throw away eof stuff - not interesting */ 727 totalreadchars += numchar; 728 totalreadlines += numline; 729 totalreadblocks += numblock; 730 totalreadfiles ++; 731 if(xflag && vflag && ok) { 732 fprintf(stdout,"x - %s: %d lines (%d chars) in %d tape blocks\n", 733 filename,numline,numchar,numblock); 734 } else if(tflag && ok) { 735 fprintf(stdout,"t - %s: %d lines (%d chars) in %d tape blocks\n", 736 filename,numline,numchar,numblock); 737 } 738 free(ibufstart); 739 return(0); 740 } 741 742 filecheck(file,name) 743 int *file; 744 char *name; 745 746 { 747 748 struct stat buf; 749 struct exec sample; 750 751 stat(name,&buf); 752 if ((buf.st_mode & S_IFDIR)==S_IFDIR) { 753 fprintf(stderr,"%s: directory - skipped\n",name); 754 return(1); 755 } 756 if ((buf.st_mode & S_IFCHR)==S_IFCHR) { 757 fprintf(stderr,"%s: character device - skipped\n",name); 758 return(1); 759 } 760 if ((buf.st_mode & S_IFBLK)==S_IFBLK) { 761 fprintf(stderr,"%s: block device - skipped\n",name); 762 return(1); 763 } 764 if ((buf.st_mode & S_IFLNK)==S_IFLNK) { 765 fprintf(stderr,"%s: symbolic link - skipped\n",name); 766 return(1); 767 } 768 if ((buf.st_mode & S_IFSOCK)==S_IFSOCK) { 769 fprintf(stderr,"%s: socket - skipped\n",name); 770 return(1); 771 } 772 *file = open(name,O_RDONLY,NULL); 773 if(*file <0) { 774 perror(name); 775 return(1); 776 } 777 if(read(*file,&sample,sizeof(struct exec))>= sizeof(struct exec)) { 778 if(!(N_BADMAG(sample))) { 779 /* executable */ 780 /* the format requires either fixed blocked records, 781 * or variable format records with each record remaining 782 * entirely within a tape block - this limits the 783 * distance between \n's to 2044 bytes, something 784 * which is VERY rarely true of executables, so 785 * we don't even try with them.... 786 */ 787 close(*file); 788 fprintf(stderr,"%s: executable - skipped\n",name); 789 return(1); 790 } 791 } 792 /* either couldn't read sizeof(struct exec) or wasn't executable */ 793 /* so we assume it is a reasonable file until proven otherwise */ 794 lseek(*file,0l,0); 795 return(0); 796 } 797