SHARE |
|
Command Line Tricks 9-Track Tape Read |
by Bill Degnan - 07/03/2026 17:49 |
|
There is a program out there called tapeutils that you can download and run from your linux box to read/dump 9-track tapes via SCSI interface but if it bombs it's hard to tell why. Here are a few commands that might help pinpoint the problem:
mt -f /dev/nst0 status (reports tape format and status of connection) mt -f /dev/nst0 rewind (rewinds tape) mt -f /dev/nst0 offline (takes the drive offline) mt -f /dev/nst0 setblk 0 (sets to variable block mode) dd if=/dev/nst0 bs=32768 count=1 of=tapenamehere.bin (read tape and save as tapenamehere.bin) mt -f /dev/nst0 fsf 1 - ( finds a start of file, runs through entire tape.) sg_raw -vv /dev/sg2 11 00 00 00 0A 00 - (force the tape to physically move ahead 0A's worth of space. The larger the hex number the more the space moved ahead. I ended up using 01 as my spacer in the C program, much less than 0A). Reply |
|
Program for Reading 9-track Tapes |
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 |
|