xref: /csrg-svn/contrib/ansi/ansitape.c (revision 30880)
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 #define getsize(a) ((a[0]-'0')*1000)+((a[1]-'0')*100)+((a[2]-'0')*10)+(a[3]-'0')
506 int
507 readfile(tape,argc,argv)
508 	int tape;
509 	int argc;
510 	char *argv[];
511 {
512 char buf[80];
513 char mode;
514 char filename[18];
515 FILE *file;
516 int extract;
517 char *ibuf;
518 char *ibufstart;
519 char *endibuf;
520 int i;
521 int size;
522 int numblock = 0 ;
523 int numchar = 0 ;
524 int numline = 0 ;
525 int argnum;
526 int ok;
527 int blocksize;
528 int recordsize;
529 int 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 
632 filecheck(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 }
687