xref: /csrg-svn/contrib/ansi/ansitape.c (revision 30881)
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 int wflag;
13 int xflag;
14 int tflag;
15 int cflag;
16 int vflag;
17 int dflag;
18 int totalreadfiles = 0 ;
19 int totalreadblocks = 0 ;
20 int totalreadlines = 0 ;
21 int totalreadchars = 0 ;
22 int totalwritefiles = 0 ;
23 int totalwriteblocks = 0 ;
24 int totalwritelines = 0 ;
25 int totalwritechars = 0 ;
26 
27 main(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 }
225 usage() {
226 	fprintf(stderr,
227 			"ansitape: usage: ansitape -{rxtc}[flnvb] [filename] [label] [filename] [blocksize] [files]\n");
228 	exit();
229 }
230 
231 writefile(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 
256 writedata(tape,file,filename,blocks,blocksize)
257 	int tape;
258 	int file;
259 	char *filename;
260 	int *blocks;
261 	int blocksize;
262 {
263 char *ibuf;
264 char *ibufstart;
265 char *obuf;
266 char *obufstart;
267 char sizebuf[5];
268 char *endibuf;
269 char *endobuf;
270 int got;
271 int i;
272 char *j;
273 int numchar = 0 ;
274 int numline = 0 ;
275 int numblock = 0;
276 int 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 
369 writetm(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 
378 rewind(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 
387 skipfile(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 
396 backspace(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 
405 writehdr1(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 
420 writeeof1(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 
436 writehdr2(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 
445 writeeof2(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 
454 writehdr3(tape)
455 	int tape;
456 {
457 	char buf[81];
458 	sprintf(buf, "HDR3%76.76s"," ");
459 	write(tape,buf,80);
460 }
461 
462 writeeof3(tape)
463 	int tape;
464 {
465 	char buf[81];
466 	sprintf(buf, "EOF3%76.76s"," ");
467 	write(tape,buf,80);
468 }
469 
470 writevol(tapename,tape)
471 	int tape;
472 	char *tapename;
473 {
474 	char buf[81];
475 	sprintf(buf,"VOL1%-6.6s %26.26sD%47510.10s1%28.28s3",tapename," "," "," ");
476 	write(tape,buf,80);
477 	if(vflag) {
478 		fprintf(stdout," tape labeled %-6.6s\n",tapename);
479 	}
480 }
481 
482 getvol(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 
494 casefix(string)
495     register char *string;
496 {
497     while(*string) {
498         if(islower(*string)) {
499             *string = toupper(*string);
500         }
501         string++;
502     }
503 }
504 
505 static
506 getsize(a)
507 	register char *a;
508 {
509 	register int	i;
510 	int		answer;
511 
512 	answer = 0;
513 	for (i = 0; i < 4; ++i) {
514 		answer *= 10;
515 		switch (a[i]) {
516 			default:	return -1;
517 			case '0':	break;
518 			case '1':	answer += 1; break;
519 			case '2':	answer += 2; break;
520 			case '3':	answer += 3; break;
521 			case '4':	answer += 4; break;
522 			case '5':	answer += 5; break;
523 			case '6':	answer += 6; break;
524 			case '7':	answer += 7; break;
525 			case '8':	answer += 8; break;
526 			case '9':	answer += 9; break;
527 		}
528 	}
529 	return(answer);
530 }
531 
532 int
533 readfile(tape,argc,argv)
534 	int tape;
535 	int argc;
536 	char *argv[];
537 {
538 char buf[80];
539 char mode;
540 char filename[18];
541 FILE *file;
542 int extract;
543 char *ibuf;
544 char *ibufstart;
545 char *endibuf;
546 int i;
547 int size;
548 int numblock = 0 ;
549 int numchar = 0 ;
550 int numline = 0 ;
551 int argnum;
552 int ok;
553 int blocksize;
554 int recordsize;
555 int writeblock;
556 
557 	if(!(read(tape,buf,80))) return(1); /* no hdr record, so second eof */
558 	sscanf(buf,"HDR1%17s",filename);
559 	read(tape,buf,80);
560 	sscanf(buf,"HDR2%c%5d%5d",&mode,&blocksize,&recordsize);
561 	blocksize = blocksize>recordsize?blocksize:recordsize;
562 	skipfile(tape); /* throw away rest of header(s) - not interesting */
563 	ibufstart=ibuf=malloc(blocksize+10);
564 	endibuf=ibufstart+blocksize;
565 	extract=0;
566 	if(tflag || xflag) {
567 		ok=0;
568 		if(!argc) {
569 			ok=1;
570 		} else for(argnum=0;argnum<argc;argnum++) {
571 			casefix(argv[argnum]);
572 			if(!strcmp(filename,argv[argnum])) {
573 				ok=1;
574 				break;
575 			}
576 		}
577 		if(mode == 'D') {
578 			if(xflag && ok) {
579 				file = fopen(filename,"w");
580 				if(file == NULL) {
581 					perror(filename);
582 				} else {
583 					extract = 1;
584 				}
585 			}
586 			while(read(tape,ibufstart,blocksize)) {
587 				numblock++;
588 				ibuf = ibufstart;
589 				while(strncmp("^^^^",ibuf,4)) {
590 					size = getsize(ibuf);
591 					if(size <= 0) {
592 						(void)fflush(stdout);
593 						(void)fprintf(stderr,"error: bad tape record(s) in file %s - file may be truncated/corrupted.\n", filename);
594 						break;
595 					}
596 					if(extract) {
597 						fwrite(ibuf+4,sizeof(char),size-4,file);
598 						fwrite("\n",1,1,file);
599 					}
600 					ibuf += (size);
601 					numline++;
602 					numchar += (size-4);
603 					if(ibuf > endibuf+1) {
604 						fprintf(stderr,"error:  bad tape records(s) - file may be corrupted\n");
605 						break;
606 					}
607 					if(ibuf>endibuf-4) break;
608 				}
609 			}
610 			if(extract) {
611 				fclose(file);
612 			}
613 		} else if (mode == 'F') {
614 			if(xflag && ok) {
615 				file = fopen(filename,"w");
616 				if(file == NULL) {
617 					perror(filename);
618 				} else {
619 					extract = 1;
620 				}
621 			}
622 			while(read(tape,ibufstart,blocksize)) {
623 				numblock++;
624 				ibuf = ibufstart;
625 				while(ibuf+recordsize <= endibuf) {
626 					if(extract) {
627 						fwrite(ibuf,sizeof(char),recordsize,file);
628 						fwrite("\n",1,1,file);
629 					}
630 					ibuf += recordsize;
631 					numline++;
632 					numchar += recordsize;
633 				}
634 			}
635 			if(extract) {
636 				fclose(file);
637 			}
638 		} else {
639 			fprintf(stderr,"unknown record mode (%c) - file %s skipped\n",
640 					mode,filename);
641 			skipfile(tape);	/* throw away actual file */
642 		}
643 	} else {
644 		/* not interested in contents of file, so move fast */
645 		skipfile(tape);
646 	}
647 	skipfile(tape); /* throw away eof stuff - not interesting */
648 	totalreadchars += numchar;
649 	totalreadlines += numline;
650 	totalreadblocks += numblock;
651 	totalreadfiles ++;
652 	if(xflag && vflag && ok) {
653 		fprintf(stdout,"x - %s:  %d lines (%d chars) in %d tape blocks\n",
654 				filename,numline,numchar,numblock);
655 	} else if(tflag && ok) {
656 		fprintf(stdout,"t - %s:  %d lines (%d chars) in %d tape blocks\n",
657 				filename,numline,numchar,numblock);
658 	}
659 	free(ibufstart);
660 	return(0);
661 }
662 
663 filecheck(file,name)
664 	int *file;
665 	char *name;
666 
667 {
668 
669 	struct stat buf;
670 	struct exec sample;
671 
672 	stat(name,&buf);
673 	if ((buf.st_mode & S_IFDIR)==S_IFDIR) {
674 		fprintf(stderr,"%s: directory - skipped\n",name);
675 		return(1);
676 	}
677 	if ((buf.st_mode & S_IFCHR)==S_IFCHR) {
678 		fprintf(stderr,"%s: character device - skipped\n",name);
679 		return(1);
680 	}
681 	if ((buf.st_mode & S_IFBLK)==S_IFBLK) {
682 		fprintf(stderr,"%s: block device - skipped\n",name);
683 		return(1);
684 	}
685 	if ((buf.st_mode & S_IFLNK)==S_IFLNK) {
686 		fprintf(stderr,"%s: symbolic link - skipped\n",name);
687 		return(1);
688 	}
689 	if ((buf.st_mode & S_IFSOCK)==S_IFSOCK) {
690 		fprintf(stderr,"%s: socket - skipped\n",name);
691 		return(1);
692 	}
693 	*file = open(name,O_RDONLY,NULL);
694 	if(*file <0) {
695 		perror(name);
696 		return(1);
697 	}
698 	if(read(*file,&sample,sizeof(struct exec))>= sizeof(struct exec)) {
699 		if(!(N_BADMAG(sample))) {
700 			/* executable */
701 			/* the format requires either fixed blocked records,
702 			 * or variable format records with each record remaining
703 			 * entirely within a tape block - this limits the
704 			 * distance between \n's to 2044 bytes, something
705 			 * which is VERY rarely true of executables, so
706 			 * we don't even try with them....
707 			 */
708 			close(*file);
709 			fprintf(stderr,"%s: executable - skipped\n",name);
710 			return(1);
711 		}
712 	}
713 	/* either couldn't read sizeof(struct exec) or wasn't executable */
714 	/* so we assume it is a reasonable file until proven otherwise */
715 	lseek(*file,0l,0);
716 	return(0);
717 }
718