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