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