SHARE |
|
|
by Bill Degnan - 07/03/2026 17:56 |
|
Tom Hunter sent me a C program for reading 9-track tapes attached via SCSI to a linux PC. I updated it to try 5 times if the tape does not read and then physically move the tape forward a hair to try a new section of tape, assuming the tape is bad. It assumes the location of the 9-track drive in linux is called /dev/nst0. I used this program to read 800, 1600 PE and 6250 bpi tapes in an M4 9914 9-track drive.
/* * recovertap_v2.c * * Tape recovery tool for problematic 9-track SCSI tape drives. * * Behavior: * - Reads from /dev/nst0 * - Writes recovered data to output file * - On read error (EIO): * issues SCSI SPACE command via sg_raw * retries read * - Never exits on single read error * - Logs all actions * * Compile: * gcc -Wall -O2 recovertap_v2.c -o recovertap_v2 * * Run: * sudo ./recovertap_v2 output.bin */ /* replace the weird brackets with real ones.*/ #include 〱stdio.h> #include 〱stdlib.h> #include 〱unistd.h> #include 〱fcntl.h> #include 〱errno.h> #include 〱string.h> #include 〱sys/types.h> #include 〱sys/stat.h> #define BSIZE 32768 #define MAX_ERRORS 50 unsigned char buf[BSIZE]; void space_tape() { /* Fixed SPACE command we already verified works */ printf(">>> SPACE 10 records "); system("sg_raw /dev/sg2 11 00 00 00 01 00"); } int main(int argc, char *argv[]) { int mt; FILE *of; int rc; long records = 0; long bytes = 0; int errors = 0; if (argc != 2) { fprintf(stderr, "Usage: %s output_file ", argv[0]); return 1; } mt = open("/dev/nst0", O_RDONLY); if (mt < 0) { perror("open /dev/nst0"); return 1; } of = fopen(argv[1], "wb"); if (!of) { perror("open output"); close(mt); return 1; } printf("Starting recovery... "); while (1) { rc = read(mt, buf, BSIZE); if (rc > 0) { errors = 0; records++; bytes += rc; printf("OK Record %ld (%d bytes) ", records, rc); fwrite(buf, 1, rc, of); fflush(of); continue; } if (rc == 0) { printf("Tape Mark detected "); continue; } /* ERROR CASE */ errors++; printf(" *** READ ERROR #%d *** ", errors); printf("errno: %d (%s) ", errno, strerror(errno)); if (errno != EIO) { printf("Non-I/O error, stopping. "); break; } /* This is the key recovery mechanism */ sleep(1); space_tape(); printf("Retrying read... "); sleep(1); if (errors >= MAX_ERRORS) { printf("Too many consecutive errors. Stopping. "); break; } } printf(" --- SUMMARY --- "); printf("Records read : %ld ", records); printf("Bytes read : %ld ", bytes); printf("Errors : %d ", errors); fclose(of); close(mt); return 0; } Reply |
|