1 /* TAPECOPY.C (c) Copyright Roger Bowler, 1999-2010 */
2 /* Convert SCSI tape into AWSTAPE format */
3
4 /* Read from AWSTAPE and write to SCSI tape mods */
5 /* Copyright 2005-2009 James R. Maynard III */
6
7 /*-------------------------------------------------------------------*/
8 /* This program reads a SCSI tape and produces a disk file with */
9 /* each block of the tape prefixed by an AWSTAPE block header. */
10 /* If no disk file name is supplied, then the program simply */
11 /* prints a summary of the tape files and blocksizes. */
12 /*-------------------------------------------------------------------*/
13
14 #include "hstdinc.h"
15
16 #include "hercules.h"
17 #include "tapedev.h"
18 #include "scsitape.h"
19
20 /*-------------------------------------------------------------------*/
21 /* (if no SCSI tape support generated, do nothing) */
22 /*-------------------------------------------------------------------*/
23 #if !defined(OPTION_SCSI_TAPE)
24 // SYSBLK sysblk;
main(int argc,char * argv[])25 int main (int argc, char *argv[])
26 {
27 UNREFERENCED(argc);
28 UNREFERENCED(argv);
29 printf( _("HHCTC017E SCSI tape not supported with this build\n") );
30 return 0;
31 }
32 #else
33
34 /*-------------------------------------------------------------------*/
35 /* External GUI flag... */
36 /*-------------------------------------------------------------------*/
37 #if defined(EXTERNALGUI)
38 time_t curr_progress_time = 0;
39 time_t prev_progress_time = 0;
40 #define PROGRESS_INTERVAL_SECS ( 3 ) /* (just what it says) */
41 #endif /*defined(EXTERNALGUI)*/
42
43
44 /*-------------------------------------------------------------------*/
45 /* Return Codes... */
46 /*-------------------------------------------------------------------*/
47 #define RC_SUCCESS ( 0)
48 #define RC_ERROR_BAD_ARGUMENTS ( 1)
49 #define RC_ERROR_OPENING_SCSI_DEVICE ( 3)
50 #define RC_ERROR_OPENING_AWS_FILE ( 4)
51 #define RC_ERROR_SETTING_SCSI_VARBLK_PROCESSING ( 5)
52 #define RC_ERROR_REWINDING_SCSI ( 6)
53 #define RC_ERROR_OBTAINING_SCSI_STATUS ( 7)
54 #define RC_ERROR_READING_AWS_HEADER ( 8)
55 #define RC_ERROR_READING_DATA ( 9)
56 #define RC_ERROR_AWSTAPE_BLOCK_TOO_LARGE (10)
57 #define RC_ERROR_WRITING_TAPEMARK (11)
58 #define RC_ERROR_WRITING_OUTPUT_AWS_HEADER_BLOCK (12)
59 #define RC_ERROR_WRITING_DATA (13)
60
61 /*-------------------------------------------------------------------*/
62 /* Static data areas */
63 /*-------------------------------------------------------------------*/
64 static BYTE vollbl[] = "\xE5\xD6\xD3"; /* EBCDIC characters "VOL" */
65 static BYTE hdrlbl[] = "\xC8\xC4\xD9"; /* EBCDIC characters "HDR" */
66 static BYTE eoflbl[] = "\xC5\xD6\xC6"; /* EBCDIC characters "EOF" */
67 static BYTE eovlbl[] = "\xC5\xD6\xE5"; /* EBCDIC characters "EOV" */
68
69 static struct mt_tape_info tapeinfo[] = MT_TAPE_INFO;
70
71 static struct mt_tape_info densinfo[] =
72 {
73 {0x01, "NRZI (800 bpi)" },
74 {0x02, "PE (1600 bpi)" },
75 {0x03, "GCR (6250 bpi)" },
76 {0x05, "QIC-45/60 (GCR, 8000 bpi)" },
77 {0x06, "PE (3200 bpi)" },
78 {0x07, "IMFM (6400 bpi)" },
79 {0x08, "GCR (8000 bpi)" },
80 {0x09, "GCR (37871 bpi)" },
81 {0x0A, "MFM (6667 bpi)" },
82 {0x0B, "PE (1600 bpi)" },
83 {0x0C, "GCR (12960 bpi)" },
84 {0x0D, "GCR (25380 bpi)" },
85 {0x0F, "QIC-120 (GCR 10000 bpi)" },
86 {0x10, "QIC-150/250 (GCR 10000 bpi)" },
87 {0x11, "QIC-320/525 (GCR 16000 bpi)" },
88 {0x12, "QIC-1350 (RLL 51667 bpi)" },
89 {0x13, "DDS (61000 bpi)" },
90 {0x14, "EXB-8200 (RLL 43245 bpi)" },
91 {0x15, "EXB-8500 (RLL 45434 bpi)" },
92 {0x16, "MFM 10000 bpi" },
93 {0x17, "MFM 42500 bpi" },
94 {0x24, "DDS-2" },
95 {0x8C, "EXB-8505 compressed" },
96 {0x90, "EXB-8205 compressed" },
97 {0, NULL },
98 };
99
100 /*-------------------------------------------------------------------*/
101 /* Maximum blocksized SCSI tape I/O buffer... */
102 /*-------------------------------------------------------------------*/
103 static BYTE buf[ 65535 ];
104
105 /*-------------------------------------------------------------------*/
106 /* Global variables used by main and the read/write functions */
107 /*-------------------------------------------------------------------*/
108 int len; /* Block length */
109 int prevlen; /* Previous block length */
110 int64_t bytes_written; /* Bytes written to o/p file */
111 char *devnamein; /* -> Input tape device name */
112 char *devnameout; /* -> Output tape device name*/
113 char *filenamein; /* -> Input AWS file name */
114 char *filenameout; /* -> Output AWS file name */
115
116 /*-------------------------------------------------------------------*/
117 /* Custom exit function... */
118 /*-------------------------------------------------------------------*/
delayed_exit(int exit_code)119 void delayed_exit (int exit_code)
120 {
121 if (RC_SUCCESS != exit_code)
122 printf( _( "HHCTC000I Abnormal termination\n" ) );
123
124 /* Delay exiting is to give the system
125 * time to display the error message. */
126 usleep(100000);
127 exit(exit_code);
128 }
129 #define EXIT(rc) delayed_exit(rc) /* (use this macro to exit) */
130
131 /*-------------------------------------------------------------------*/
132 /* Subroutine to print tape status */
133 /*-------------------------------------------------------------------*/
print_status(char * devname,long stat)134 static void print_status (char *devname, long stat)
135 {
136 printf (_("HHCTC015I %s status: %8.8lX"), devname, stat);
137
138 if (GMT_EOF ( stat )) printf (" EOF" );
139 if (GMT_BOT ( stat )) printf (" BOT" );
140 if (GMT_EOT ( stat )) printf (" EOT" );
141 if (GMT_SM ( stat )) printf (" SETMARK");
142 if (GMT_EOD ( stat )) printf (" EOD" );
143 if (GMT_WR_PROT( stat )) printf (" WRPROT" );
144 if (GMT_ONLINE ( stat )) printf (" ONLINE" );
145 if (GMT_D_6250 ( stat )) printf (" 6250" );
146 if (GMT_D_1600 ( stat )) printf (" 1600" );
147 if (GMT_D_800 ( stat )) printf (" 800" );
148 if (GMT_DR_OPEN( stat )) printf (" NOTAPE" );
149
150 printf ("\n");
151
152 } /* end function print_status */
153
154 /*-------------------------------------------------------------------*/
155 /* Subroutine to print usage message */
156 /*-------------------------------------------------------------------*/
print_usage(void)157 static void print_usage (void)
158 {
159 printf
160 ( _(
161 "\n"
162 // 1...5...10...15...20...25...30...35...40...45...50...55...60...65...70...75...80
163 "Copies a SCSI tape to or from an AWSTAPE disk file.\n\n"
164
165 "Tapecopy reads a SCSI tape and outputs an AWSTAPE file representation\n"
166 "of the tape, or else reads an AWSTAPE file and creates an identical copy\n"
167 "of its contents on a tape mounted on a SCSI tape drive.\n\n"
168
169 "Usage:\n\n"
170
171 " tapecopy [tapedrive] [awsfile] or\n"
172 " tapecopy [awsfile] [tapedrive]\n\n"
173
174 "Where:\n\n"
175
176 " tapedrive specifies the device filename of the SCSI tape drive.\n"
177 " Must begin with /dev%s to be recognized.\n"
178 " awsfile specifies the filename of the AWSTAPE disk file.\n\n"
179
180 "The first filename is the input; the second is the output.\n\n"
181
182 "If the input file is a SCSI tape, it is read and processed until physical EOD\n"
183 "(end-of-data) is reached (i.e. it does not stop whenever multiple tapemarks or\n"
184 "filemarks are read; it continues processing until the SCSI tape drive says\n"
185 "there is no more data on the tape). The resulting AWSTAPE output disk file,\n"
186 "when specified for the filename on a Hercules tape device configuration\n"
187 "statement, can then be used instead in order for the Hercules guest O/S to\n"
188 "read the exact same data without having to have a SCSI tape drive physically\n"
189 "attached to the host system. This allows you to easily transfer SCSI tape data\n"
190 "to other systems that may not have SCSI tape drives attached to them.\n\n"
191
192 "The possible return codes and their meaning are:\n\n"
193
194 " %2d Successful completion.\n"
195 " %2d Invalid arguments or no arguments given.\n"
196 " %2d Unable to open SCSI tape drive device file.\n"
197 " %2d Unable to open AWSTAPE disk file.\n"
198 " %2d Unrecoverable I/O error setting variable length block\n"
199 " processing for SCSI tape device.\n"
200 " %2d Unrecoverable I/O error rewinding SCSI tape device.\n"
201 " %2d Unrecoverable I/O error obtaining status of SCSI device.\n"
202 " %2d Unrecoverable I/O error reading block header\n"
203 " from AWSTAPE disk file.\n"
204 " %2d Unrecoverable I/O error reading data block.\n"
205 " %2d AWSTAPE block size too large.\n"
206 " %2d Unrecoverable I/O error writing tapemark.\n"
207 " %2d Unrecoverable I/O error writing block header\n"
208 " to AWSTAPE disk file.\n"
209 " %2d Unrecoverable I/O error writing data block.\n"
210 "\n"
211 )
212
213 #if defined(_MSVC_)
214 ," or \\\\.\\Tape"
215 #else
216 ,""
217 #endif
218 ,RC_SUCCESS
219 ,RC_ERROR_BAD_ARGUMENTS
220 ,RC_ERROR_OPENING_SCSI_DEVICE
221 ,RC_ERROR_OPENING_AWS_FILE
222 ,RC_ERROR_SETTING_SCSI_VARBLK_PROCESSING
223
224 ,RC_ERROR_REWINDING_SCSI
225 ,RC_ERROR_OBTAINING_SCSI_STATUS
226 ,RC_ERROR_READING_AWS_HEADER
227 ,RC_ERROR_READING_DATA
228 ,RC_ERROR_AWSTAPE_BLOCK_TOO_LARGE
229 ,RC_ERROR_WRITING_TAPEMARK
230
231 ,RC_ERROR_WRITING_OUTPUT_AWS_HEADER_BLOCK
232
233 ,RC_ERROR_WRITING_DATA
234 );
235
236 } /* end function print_usage */
237
238 /*-------------------------------------------------------------------*/
239 /* Subroutine to obtain SCSI tape status... */
240 /* */
241 /* Return value: 0 == normal */
242 /* +1 == end-of-tape */
243 /* -1 == error */
244 /*-------------------------------------------------------------------*/
obtain_status(char * devname,int devfd,struct mtget * mtget)245 static int obtain_status (char *devname, int devfd, struct mtget* mtget)
246 {
247 int rc; /* Return code */
248
249 rc = ioctl_tape (devfd, MTIOCGET, (char*)mtget);
250 if (rc < 0)
251 {
252 if (1
253 && EIO == errno
254 && (0
255 || GMT_EOD( mtget->mt_gstat )
256 || GMT_EOT( mtget->mt_gstat )
257 )
258 )
259 return +1;
260
261 printf (_("HHCTC016E Error reading status of %s: rc=%d, errno=%d: %s\n"),
262 devname, rc, errno, strerror(errno));
263 return -1;
264 }
265
266 if (GMT_EOD( mtget->mt_gstat ) ||
267 GMT_EOT( mtget->mt_gstat ))
268 return +1;
269
270 return 0;
271 } /* end function obtain_status */
272
273 /*-------------------------------------------------------------------*/
274 /* Read a block from SCSI tape */
275 /*-------------------------------------------------------------------*/
read_scsi_tape(int devfd,void * buf,size_t bufsize,struct mtget * mtget)276 int read_scsi_tape (int devfd, void *buf, size_t bufsize, struct mtget* mtget)
277 {
278 int rc;
279 int save_errno;
280
281 len = read_tape (devfd, buf, bufsize);
282 if (len < 0)
283 {
284 /* Determine whether end-of-tape has been read */
285 save_errno = errno;
286 ASSERT( devnamein );
287 rc = obtain_status (devnamein, devfd, mtget);
288 if (rc == +1)
289 {
290 printf (_("HHCTC011I End of tape.\n"));
291 errno = save_errno;
292 return(-1);
293 }
294 printf (_("HHCTC008E Error reading %s: errno=%d: %s\n"),
295 devnamein, errno, strerror(errno));
296 EXIT( RC_ERROR_READING_DATA );
297 }
298
299 return(len);
300 } /* end function read_scsi_tape */
301
302 /*-------------------------------------------------------------------*/
303 /* Read a block from AWSTAPE disk file */
304 /*-------------------------------------------------------------------*/
read_aws_disk(int diskfd,void * buf,size_t bufsize)305 int read_aws_disk (int diskfd, void *buf, size_t bufsize)
306 {
307 AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */
308 int rc;
309 unsigned int count_read = 0;
310 unsigned int blksize;
311 int end_block;
312 BYTE *bufptr = buf;
313
314 while (1)
315 {
316 /* Read block header */
317 rc = read (diskfd, &awshdr, sizeof(AWSTAPE_BLKHDR));
318 if (rc == 0)
319 {
320 printf (_("HHCTC018I End of AWSTAPE input file.\n"));
321 return (-1);
322 }
323 if (rc < (int)sizeof(AWSTAPE_BLKHDR))
324 {
325 printf (_("HHCTC019E Error reading AWSTAPE header from %s: rc=%d, errno=%d: %s\n"),
326 filenamein, rc, errno, strerror(errno));
327 EXIT( RC_ERROR_READING_AWS_HEADER );
328 } /* end if(rc) */
329
330 /* Interpret the block header */
331 blksize = ((int)awshdr.curblkl[1] << 8) + awshdr.curblkl[0];
332 end_block = (awshdr.flags1 & AWSTAPE_FLAG1_ENDREC) != 0;
333
334 /* If this is a tapemark, return immediately */
335 if (blksize == 0)
336 return (0);
337
338 /* Check maximum block length */
339 if ((count_read + blksize) > bufsize)
340 {
341 printf (_("HHCTC020E AWSTAPE block too large on %s: block size=%d, maximum=%d\n"),
342 filenamein, count_read+blksize, (int)bufsize);
343 EXIT( RC_ERROR_AWSTAPE_BLOCK_TOO_LARGE );
344 } /* end if(count) */
345
346 /* Read data block */
347 rc = read (diskfd, bufptr, blksize);
348 if (rc < (int)blksize)
349 {
350 printf (_("HHCTC021E Error reading data block from %s: rc=%d, errno=%d: %s\n"),
351 filenamein, rc, errno, strerror(errno));
352 EXIT( RC_ERROR_READING_DATA );
353 } /* end if(rc) */
354
355 bufptr += blksize;
356 count_read += blksize;
357 if (end_block)
358 break;
359 }
360
361 return(count_read);
362
363 } /* end function read_aws_disk */
364
365 /*-------------------------------------------------------------------*/
366 /* Write a block to SCSI tape */
367 /*-------------------------------------------------------------------*/
write_scsi_tape(int devfd,void * buf,size_t len)368 int write_scsi_tape (int devfd, void *buf, size_t len)
369 {
370 int rc;
371
372 rc = write_tape (devfd, buf, len);
373 if (rc < (int)len)
374 {
375 printf (_("HHCTC022E Error writing data block to %s: rc=%d, errno=%d: %s\n"),
376 devnameout, rc, errno, strerror(errno));
377 EXIT( RC_ERROR_WRITING_DATA );
378 } /* end if(rc) */
379
380 bytes_written += rc;
381
382 return(rc);
383
384 } /* end function write_scsi_tape */
385
386 /*-------------------------------------------------------------------*/
387 /* Write a block to AWSTAPE disk file */
388 /*-------------------------------------------------------------------*/
write_aws_disk(int diskfd,void * buf,size_t len)389 int write_aws_disk (int diskfd, void *buf, size_t len)
390 {
391 AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */
392 int rc;
393
394 /* Build the block header */
395 awshdr.curblkl[0] = len & 0xFF;
396 awshdr.curblkl[1] = ( len >> 8 ) & 0xFF;
397 awshdr.prvblkl[0] = prevlen & 0xFF;
398 awshdr.prvblkl[1] = ( prevlen >> 8 ) & 0xFF;
399 awshdr.flags1 = 0
400 | AWSTAPE_FLAG1_NEWREC
401 | AWSTAPE_FLAG1_ENDREC
402 ;
403 awshdr.flags2 = 0;
404
405 /* Write block header to output file */
406 rc = write (diskfd, &awshdr, sizeof(AWSTAPE_BLKHDR));
407 if (rc < (int)sizeof(AWSTAPE_BLKHDR))
408 {
409 printf (_("HHCTC013E Error writing AWSTAPE header on %s: rc=%d, errno=%d: %s\n"),
410 filenameout, rc, errno, strerror(errno));
411 EXIT( RC_ERROR_WRITING_OUTPUT_AWS_HEADER_BLOCK );
412 } /* end if(rc) */
413
414 bytes_written += rc;
415
416 /* Write data block to output file */
417 rc = write (diskfd, buf, len);
418 if (rc < (int)len)
419 {
420 printf (_("HHCTC014E Error writing data block to %s: rc=%d, errno=%d: %s\n"),
421 filenameout, rc, errno, strerror(errno));
422 EXIT( RC_ERROR_WRITING_DATA );
423 } /* end if(rc) */
424
425 bytes_written += rc;
426
427 return(rc);
428 } /* end function write_aws_disk */
429
430 /*-------------------------------------------------------------------*/
431 /* Write a tapemark to SCSI tape */
432 /*-------------------------------------------------------------------*/
write_tapemark_scsi_tape(int devfd)433 int write_tapemark_scsi_tape (int devfd)
434 {
435 struct mtop opblk; /* Area for MTIOCTOP ioctl */
436 int rc;
437
438 opblk.mt_op = MTWEOF;
439 opblk.mt_count = 1;
440 rc = ioctl_tape (devfd, MTIOCTOP, (char*)&opblk);
441 if (rc < 0)
442 {
443 printf (_("HHCTC023E Error writing tapemark on %s: rc=%d, errno=%d: %s\n"),
444 devnameout, rc, errno, strerror(errno));
445 EXIT( RC_ERROR_WRITING_TAPEMARK );
446 }
447 return(rc);
448
449 } /* end function write_tapemark_scsi_tape */
450
451 /*-------------------------------------------------------------------*/
452 /* Write a tapemark to AWSTAPE disk file */
453 /*-------------------------------------------------------------------*/
write_tapemark_aws_disk(int diskfd)454 int write_tapemark_aws_disk (int diskfd)
455 {
456 AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */
457 int rc;
458
459 /* Build block header for tape mark */
460 awshdr.curblkl[0] = 0;
461 awshdr.curblkl[1] = 0;
462 awshdr.prvblkl[0] = prevlen & 0xFF;
463 awshdr.prvblkl[1] = ( prevlen >> 8 ) & 0xFF;
464 awshdr.flags1 = AWSTAPE_FLAG1_TAPEMARK;
465 awshdr.flags2 = 0;
466
467 /* Write block header to output file */
468 rc = write (diskfd, &awshdr, sizeof(AWSTAPE_BLKHDR));
469 if (rc < (int)sizeof(AWSTAPE_BLKHDR))
470 {
471 printf (_("HHCTC010E Error writing tapemark on %s: rc=%d, errno=%d, %s\n"),
472 filenameout, rc, errno, strerror(errno));
473 EXIT( RC_ERROR_WRITING_TAPEMARK );
474 } /* end if(rc) */
475
476 bytes_written += rc;
477 return(rc);
478 } /* end function write_tapemark_aws_disk */
479
480 /*-------------------------------------------------------------------*/
481 /* TAPECOPY main entry point */
482 /*-------------------------------------------------------------------*/
main(int argc,char * argv[])483 int main (int argc, char *argv[])
484 {
485 int rc; /* Return code */
486 int i; /* Array subscript */
487 int devfd; /* Tape file descriptor */
488 int diskfd = -1; /* Disk file descriptor */
489 int fileno; /* Tape file number */
490 int blkcount; /* Block count */
491 int totalblks = 0; /* Block count */
492 int minblksz; /* Minimum block size */
493 int maxblksz; /* Maximum block size */
494 struct mtop opblk; /* Area for MTIOCTOP ioctl */
495 long density; /* Tape density code */
496 BYTE labelrec[81]; /* Standard label (ASCIIZ) */
497 int64_t bytes_read; /* Bytes read from i/p file */
498 int64_t file_bytes; /* Byte count for curr file */
499 char pathname[MAX_PATH]; /* file name in host format */
500 struct mtget mtget; /* Area for MTIOCGET ioctl */
501 #if defined(EXTERNALGUI)
502 struct mtpos mtpos; /* Area for MTIOCPOS ioctl */
503 int is3590 = 0; /* 1 == 3590, 0 == 3480/3490 */
504 #endif /*defined(EXTERNALGUI)*/
505
506 INITIALIZE_UTILITY("tapecopy");
507
508 /* Display the program identification message */
509 display_version (stderr, "Hercules tape copy program ", FALSE);
510
511 /* The first argument is the input file name
512 (either AWS disk file or SCSI tape device)
513 */
514 if ((argc < 2) || (argv[1] == NULL))
515 {
516 print_usage();
517 EXIT( RC_ERROR_BAD_ARGUMENTS );
518 return(0); /* Make gcc -Wall happy */
519 }
520
521 if (0
522 || ( strlen( argv[1] ) > 5 && strnfilenamecmp( argv[1], "/dev/", 5 ) == 0 )
523 || ( strlen( argv[1] ) > 4 && strnfilenamecmp( argv[1], "\\\\.\\", 4 ) == 0 )
524 )
525 {
526 devnamein = argv[1];
527 filenamein = NULL;
528 }
529 else
530 {
531 filenamein = argv[1];
532 devnamein = NULL;
533 }
534
535 /* The second argument is the output file name
536 (either AWS disk file or SCSI tape device)
537 */
538 if (argc > 2 && argv[2] )
539 {
540 if (0
541 || ( strlen( argv[2] ) > 5 && strnfilenamecmp( argv[2], "/dev/", 5 ) == 0 )
542 || ( strlen( argv[2] ) > 4 && strnfilenamecmp( argv[2], "\\\\.\\", 4 ) == 0 )
543 )
544 {
545 devnameout = argv[2];
546 filenameout = NULL;
547 }
548 else
549 {
550 filenameout = argv[2];
551 devnameout = NULL;
552 }
553 }
554 else
555 {
556 print_usage();
557 EXIT( RC_ERROR_BAD_ARGUMENTS );
558 }
559
560 /* Check input arguments and disallow tape-to-tape or disk-to-disk copy */
561 if ((!devnamein && !devnameout) || (!filenamein && !filenameout))
562 {
563 print_usage();
564 EXIT( RC_ERROR_BAD_ARGUMENTS );
565 }
566
567 /* Open the SCSI tape device */
568 if (devnamein)
569 {
570 hostpath( pathname, devnamein, sizeof(pathname) );
571 devfd = open_tape (pathname, O_RDONLY|O_BINARY);
572 }
573 else // (devnameout)
574 {
575 hostpath( pathname, devnameout, sizeof(pathname) );
576 devfd = open_tape (pathname, O_RDWR|O_BINARY);
577 }
578 if (devfd < 0)
579 {
580 printf (_("HHCTC001E Error opening %s: errno=%d: %s\n"),
581 (devnamein ? devnamein : devnameout), errno, strerror(errno));
582 EXIT( RC_ERROR_OPENING_SCSI_DEVICE );
583 }
584
585 usleep(50000);
586
587 /* Set the tape device to process variable length blocks */
588 opblk.mt_op = MTSETBLK;
589 opblk.mt_count = 0;
590 rc = ioctl_tape (devfd, MTIOCTOP, (char*)&opblk);
591 if (rc < 0)
592 {
593 printf (_("HHCTC005E Error setting attributes for %s: rc=%d, errno=%d: %s\n"),
594 (devnamein ? devnamein : devnameout), rc, errno, strerror(errno));
595 EXIT( RC_ERROR_SETTING_SCSI_VARBLK_PROCESSING );
596 }
597
598 usleep(50000);
599
600 /* Rewind the tape to the beginning */
601 opblk.mt_op = MTREW;
602 opblk.mt_count = 1;
603 rc = ioctl_tape (devfd, MTIOCTOP, (char*)&opblk);
604 if (rc < 0)
605 {
606 printf (_("HHCTC006E Error rewinding %s: rc=%d, errno=%d: %s\n"),
607 (devnamein ? devnamein : devnameout), rc, errno, strerror(errno));
608 EXIT( RC_ERROR_REWINDING_SCSI );
609 }
610
611 usleep(50000);
612
613 /* Obtain the tape status */
614 rc = obtain_status ((devnamein ? devnamein : devnameout), devfd, &mtget);
615 if (rc < 0)
616 EXIT( RC_ERROR_OBTAINING_SCSI_STATUS );
617
618 /* Display tape status information */
619 for (i = 0; tapeinfo[i].t_type != 0
620 && tapeinfo[i].t_type != mtget.mt_type; i++);
621
622 if (tapeinfo[i].t_name)
623 printf (_("HHCTC003I %s device type: %s\n"),
624 (devnamein ? devnamein : devnameout), tapeinfo[i].t_name);
625 else
626 printf (_("HHCTC003I %s device type: 0x%lX\n"),
627 (devnamein ? devnamein : devnameout), mtget.mt_type);
628
629 density = (mtget.mt_dsreg & MT_ST_DENSITY_MASK)
630 >> MT_ST_DENSITY_SHIFT;
631
632 for (i = 0; densinfo[i].t_type != 0
633 && densinfo[i].t_type != density; i++);
634
635 if (densinfo[i].t_name)
636 printf (_("HHCTC004I %s tape density: %s\n"),
637 (devnamein ? devnamein : devnameout), densinfo[i].t_name);
638 else
639 printf (_("HHCTC004I %s tape density code: 0x%lX\n"),
640 (devnamein ? devnamein : devnameout), density);
641
642 if (mtget.mt_gstat != 0)
643 print_status ((devnamein ? devnamein : devnameout), mtget.mt_gstat);
644
645 /* Open the disk file */
646 if (filenamein)
647 {
648 hostpath( pathname, filenamein, sizeof(pathname) );
649 diskfd = hopen(pathname, O_RDONLY | O_BINARY);
650 }
651 else
652 {
653 hostpath( pathname, filenameout, sizeof(pathname) );
654 diskfd = hopen(pathname, O_WRONLY | O_CREAT | O_BINARY,
655 S_IRUSR | S_IWUSR | S_IRGRP);
656 }
657 if (diskfd < 0)
658 {
659 printf (_("HHCTC007E Error opening %s: errno=%d: %s\n"),
660 (filenamein ? filenamein : filenameout),
661 errno, strerror(errno));
662 EXIT( RC_ERROR_OPENING_AWS_FILE );
663 }
664
665 /* Copy blocks from input to output */
666 fileno = 1;
667 blkcount = 0;
668 totalblks = 0;
669 minblksz = 0;
670 maxblksz = 0;
671 len = 0;
672 bytes_read = 0;
673 bytes_written = 0;
674 file_bytes = 0;
675
676 #if defined(EXTERNALGUI)
677 // Notify the GUI of the high-end of the copy-progress range...
678 if ( extgui )
679 {
680 // Retrieve BOT block-id...
681 VERIFY( 0 == ioctl_tape( devfd, MTIOCPOS, (char*)&mtpos ) );
682
683 is3590 = ((mtpos.mt_blkno & 0x7F000000) != 0x01000000) ? 1 : 0;
684
685 if (!is3590)
686 {
687 // The seg# portion the SCSI tape physical
688 // block-id number values ranges from 1 to 95...
689 fprintf( stderr, "BLKS=%d\n", 95 );
690 }
691 else
692 {
693 // FIXME: 3590s (e.g. Magstar) use 32-bit block addressing,
694 // and thus its block-id does not contain a seg# value, so
695 // we must use some other technique. For now, we'll simply
696 // presume the last block on the tape is block# 0x003FFFFF
697 // (just to keep things simple).
698
699 fprintf( stderr, "BLKS=%d\n", 0x003FFFFF );
700 }
701
702 // Init time of last issued progress message
703 prev_progress_time = time( NULL );
704 }
705 #endif /*defined(EXTERNALGUI)*/
706
707 /* Perform the copy... */
708
709 while (1)
710 {
711 #if defined(EXTERNALGUI)
712 /* Issue a progress message every few seconds... */
713 if ( extgui )
714 {
715 if ( ( curr_progress_time = time( NULL ) ) >=
716 ( prev_progress_time + PROGRESS_INTERVAL_SECS ) )
717 {
718 prev_progress_time = curr_progress_time;
719 if ( ioctl_tape( devfd, MTIOCPOS, (char*)&mtpos ) == 0 )
720 {
721 if (!is3590)
722 fprintf( stderr, "BLK=%ld\n", (mtpos.mt_blkno >> 24) & 0x0000007F );
723 else
724 fprintf( stderr, "BLK=%ld\n", mtpos.mt_blkno );
725 }
726 }
727 }
728 #endif /*defined(EXTERNALGUI)*/
729
730 /* Save previous block length */
731 prevlen = len;
732
733 /* Read a block */
734 if (devnamein)
735 len = read_scsi_tape(devfd, buf, sizeof(buf), &mtget);
736 else
737 len = read_aws_disk(diskfd, buf, sizeof(buf));
738
739 /* If returned with -1, end of tape; errors are handled by the
740 read functions themselves */
741 if (len < 0)
742 break;
743
744 /* Check for tape mark */
745 if (len == 0)
746 {
747 /* Write tape mark to output file */
748 if (filenameout)
749 write_tapemark_aws_disk(diskfd);
750 else
751 write_tapemark_scsi_tape(devfd);
752
753 /* Print summary of current file */
754 if (blkcount)
755 {
756 ASSERT( file_bytes ); // (sanity check)
757
758 printf (_("HHCTC009I File %u: Blocks=%u, Bytes=%"I64_FMT"d, Block size min=%u, "
759 "max=%u, avg=%u\n"),
760 fileno, blkcount, file_bytes, minblksz, maxblksz,
761 (int)file_bytes/blkcount);
762 }
763 else
764 {
765 ASSERT( !file_bytes ); // (sanity check)
766 }
767
768 /* Show the 'tapemark' AFTER the above file summary since
769 that's the actual physical sequence of events; i.e. the
770 file data came first THEN it was followed by a tapemark */
771 printf(_(" (tapemark)\n")); // (align past HHCmsg#)
772
773 /* Reset counters for next file */
774 if (blkcount)
775 fileno++;
776 minblksz = 0;
777 maxblksz = 0;
778 blkcount = 0;
779 file_bytes = 0;
780 continue;
781 }
782
783 /* Count blocks and block sizes */
784 blkcount++;
785 totalblks++;
786 bytes_read += len;
787 file_bytes += len;
788 if (len > maxblksz) maxblksz = len;
789 if (minblksz == 0 || len < minblksz) minblksz = len;
790
791 /* Print standard labels */
792 if (1
793 && blkcount < 4
794 && len == 80
795 && (0
796 || memcmp( buf, vollbl, 3 ) == 0
797 || memcmp( buf, hdrlbl, 3 ) == 0
798 || memcmp( buf, eoflbl, 3 ) == 0
799 || memcmp( buf, eovlbl, 3 ) == 0
800 )
801 )
802 {
803 for (i=0; i < 80; i++)
804 labelrec[i] = guest_to_host(buf[i]);
805 labelrec[i] = '\0';
806 printf (_("HHCTC012I %s\n"), labelrec);
807 }
808 else
809 {
810 ASSERT(blkcount);
811
812 #if defined(EXTERNALGUI)
813 if ( !extgui )
814 #endif
815 printf( _("File %u: Block %u\r"),
816 fileno, blkcount );
817 }
818
819 /* Write block to output file */
820 if (filenameout)
821 write_aws_disk(diskfd, buf, len);
822 else
823 write_scsi_tape(devfd, buf, len);
824
825 } /* end while */
826
827 /* Print run totals, close files, and exit... */
828
829 #define ONE_MEGABYTE ( 1024 * 1024 )
830 #define HALF_MEGABYTE ( ONE_MEGABYTE / 2 )
831
832 printf
833 (
834 _(
835 "HHCTC000I Successful completion;\n"
836 " Bytes read: %"I64_FMT"d (%3.1f MB), Blocks=%u, avg=%u\n"
837 )
838 , bytes_read
839 ,(double) ( bytes_read + HALF_MEGABYTE ) / (double) ONE_MEGABYTE
840 ,totalblks
841 ,totalblks ? (int)bytes_read/totalblks : -1
842 );
843
844 printf
845 (
846 _(
847 " Bytes written: %"I64_FMT"d (%3.1f MB)\n"
848 )
849 , bytes_written
850 ,(double) ( bytes_written + HALF_MEGABYTE ) / (double) ONE_MEGABYTE
851 );
852 close (diskfd);
853
854 /* Rewind the tape back to the beginning again before exiting */
855
856 opblk.mt_op = MTREW;
857 opblk.mt_count = 1;
858
859 rc = ioctl_tape (devfd, MTIOCTOP, (char*)&opblk);
860
861 if (rc < 0)
862 {
863 printf (_("HHCTC006E Error rewinding %s: rc=%d, errno=%d: %s\n"),
864 (devnamein ? devnamein : devnameout), rc, errno, strerror(errno));
865 EXIT( RC_ERROR_REWINDING_SCSI );
866 }
867
868 close_tape (devfd);
869
870 EXIT( RC_SUCCESS );
871 return(0); /* Make -Wall happy */
872
873 } /* end function main */
874
875 #endif /* defined(OPTION_SCSI_TAPE) */
876