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 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 } 269 usage() { 270 fprintf(stderr, 271 "ansitape: usage: ansitape -{rxtc}[flnvb] [filename] [label] [filename] [blocksize] [files]\n"); 272 exit(1); 273 } 274 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 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 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 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 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%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 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 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 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