| floppy-batch.py | ||
| LICENSE.md | ||
| README.md | ||
floppy-batch.py
Batch process floppy disks by mounting, checking for files, and creating disk images with dd.
Features
- Interactive batch processing workflow for multiple floppy disks
- Automatic disk detection - monitors device and detects when disk is inserted and ready
- Duplicate prevention - tracks processed IDs and warns about duplicates
- Prompts for floppy ID before each disk
- Attempts to mount floppy with multiple filesystem types (msdos, vfat, ext2, auto)
- Checks if disk contains any files before proceeding
- Preserves volume label - reads original disk name and sets it on the image
- Creates disk images using dd or ddrescue (optional flag)
- ddrescue support - superior error recovery with detailed progress monitoring
- Intelligent fallback for damaged disks - if raw copy fails, automatically creates image and copies files one-by-one
- Partial data recovery from broken disks (copies what it can, skips unreadable files)
- Skips empty disks automatically
- Per-floppy logging - each disk gets its own detailed log file
- Comprehensive logging with timestamps and status tracking
- Handles filenames with invalid/corrupted characters gracefully
- Robust error handling with graceful degradation
- Automatic cleanup (unmounts) even on errors
- Progress display during disk imaging
- Automatic disk removal detection before proceeding to next disk
Usage
Important: This script must be run as root to access the floppy drive device.
sudo ./scripts/floppy-batch.py
sudo ./scripts/floppy-batch.py --device /dev/sde --output ./my_floppies
sudo ./scripts/floppy-batch.py --mount-point /mnt/floppy --output ./archive
sudo ./scripts/floppy-batch.py --ddrescue # Use ddrescue for better error recovery
Options
--device PATH- Floppy drive device path (default:/dev/sde)--output DIR- Output directory for disk images and log files (default:./floppy_images)--mount-point PATH- Temporary mount point for floppy disk (default:/mnt/floppy_temp)--ddrescue- Use ddrescue instead of dd for disk imaging (recommended for damaged/old disks)
Workflow
For each floppy disk:
- User Input - Script prompts for floppy ID
- Duplicate Check - Warns if ID was already processed (can override)
- Automatic Detection - Monitors device and waits for disk insertion
- Detects capacity change in
/sys/block/sde/size - Waits for drive to stabilize (3 stable readings)
- No manual confirmation needed!
- Detects capacity change in
- Mount - Script attempts to mount with multiple filesystem types
- If mount fails: Skip file check, proceed directly to raw imaging
- If mount succeeds: Continue to file check
- Check Files (if mounted) - Scans mounted disk for any files
- Decision Point (if mounted):
- If no files: Log status, unmount, mark as processed, skip imaging
- If files found: Continue to imaging
- Read Volume Label (if mounted) - Captures original disk name (if present)
- Unmount - Unmount before creating image (if was mounted)
- Create Image - Use dd to create
.imgfile named with the floppy ID- Volume label is preserved automatically in raw copy
- If dd fails: Automatic fallback to manual copy method
- Create empty 1.44MB FAT12 image with original volume label
- Mount as loop device
- Copy files one-by-one from source
- Log success/failure for each file
- Succeeds if at least one file copied
- Log Result - Write final status to log file and mark ID as processed
- Wait for Removal - Automatically detects when disk is removed
- Repeat - Return to step 1 for next disk
Exit anytime by typing q or pressing Ctrl+C.
Output Format
Directory Structure
floppy_images/
├── session.log # Session-level log (overall progress)
├── processed_ids.txt # List of already-processed IDs (prevents duplicates)
├── disk001.img # Disk image for ID: disk001 (raw dd/ddrescue copy)
├── disk001.log # Detailed log for disk001
├── disk001.map # ddrescue map file (if using --ddrescue)
├── disk002.img # Partial raw image for disk002
├── disk002_files.img # Fallback file-by-file recovery image for disk002
├── disk002.log # Detailed log for disk002
└── archive_1995.img # Disk image for ID: archive_1995
└── archive_1995.log # Detailed log for archive_1995
Log File Format
[2026-02-08 14:30:15] === Batch processing session started ===
[2026-02-08 14:30:25] [disk001] Starting processing
[2026-02-08 14:30:26] [disk001] Successfully mounted
[2026-02-08 14:30:26] [disk001] Found 5 file(s)
[2026-02-08 14:30:26] [disk001] - README.TXT
[2026-02-08 14:30:26] [disk001] - DATA.DAT
[2026-02-08 14:30:26] [disk001] - CONFIG.SYS
[2026-02-08 14:30:26] [disk001] - AUTOEXEC.BAT
[2026-02-08 14:30:26] [disk001] - DOCS/MANUAL.TXT
[2026-02-08 14:30:26] [disk001] Original volume label: BACKUP95
[2026-02-08 14:30:26] [disk001] dd image created successfully (1.41 MB)
[2026-02-08 14:30:26] [disk001] Volume label: BACKUP95
[2026-02-08 14:30:45] [disk001] SUCCESS: Disk image created
[2026-02-08 14:31:02] [disk002] Starting processing
[2026-02-08 14:31:02] [disk002] WARNING: Could not mount floppy disk
[2026-02-08 14:31:02] [disk002] Will attempt raw disk imaging without file listing
[2026-02-08 14:31:05] [disk002] ddrescue image created successfully (1.41 MB)
[2026-02-08 14:31:05] [disk002] SUCCESS: Disk image created
[2026-02-08 14:31:15] [disk003] Starting processing
[2026-02-08 14:31:15] [disk003] Successfully mounted
[2026-02-08 14:31:15] [disk003] No files found on disk - skipping
[2026-02-08 14:32:00] [damaged_disk] Starting processing
[2026-02-08 14:32:01] [damaged_disk] Successfully mounted
[2026-02-08 14:32:01] [damaged_disk] Found 3 file(s)
[2026-02-08 14:32:01] [damaged_disk] - FILE1.TXT
[2026-02-08 14:32:01] [damaged_disk] - FILE2.DAT
[2026-02-08 14:32:01] [damaged_disk] - CORRUPT.BIN
[2026-02-08 14:32:01] [damaged_disk] Original volume label: OLDDISK
[2026-02-08 14:32:05] [damaged_disk] dd failed, attempting manual file-by-file copy
[2026-02-08 14:32:05] [damaged_disk] Creating fallback image: damaged_disk_files.img
[2026-02-08 14:32:05] [damaged_disk] Creating empty 1.44MB image file
[2026-02-08 14:32:06] [damaged_disk] Formatting image as FAT12
[2026-02-08 14:32:06] [damaged_disk] Volume label set: OLDDISK
[2026-02-08 14:32:06] [damaged_disk] Setting up loop device
[2026-02-08 14:32:06] [damaged_disk] Loop device: /dev/loop0
[2026-02-08 14:32:07] [damaged_disk] Copying 3 files individually
[2026-02-08 14:32:07] [damaged_disk] ✓ FILE1.TXT
[2026-02-08 14:32:07] [damaged_disk] ✓ FILE2.DAT
[2026-02-08 14:32:08] [damaged_disk] ✗ CORRUPT.BIN - Input/output error
[2026-02-08 14:32:08] [damaged_disk] Copy complete: 2 succeeded, 1 failed
[2026-02-08 14:32:09] [damaged_disk] SUCCESS: Disk image created
[2026-02-08 14:33:00] === Batch processing session ended ===
Example Session
Standard Mode (dd)
$ sudo ./scripts/floppy-batch.py
============================================================
Floppy Disk Batch Processor
============================================================
Device: /dev/sde
Output directory: ./floppy_images
Session log: ./floppy_images/session.log
Mount point: /mnt/floppy_temp
Imaging tool: dd
============================================================
Press Ctrl+C to exit at any time
Enter floppy ID (or 'q' to quit): backup_1995
Waiting for floppy disk insertion...
(Insert disk now, detection is automatic)
Disk stabilizing... (2880 blocks)
✓ Disk detected (2880 blocks)
Mounting floppy from /dev/sde...
[2026-02-08 14:30:26] [backup_1995] Successfully mounted
[2026-02-08 14:30:26] [backup_1995] Found 12 file(s)
[2026-02-08 14:30:26] [backup_1995] - README.TXT
[2026-02-08 14:30:26] [backup_1995] - LETTER.DOC
...
Unmounting before creating image...
Creating disk image: ./floppy_images/backup_1995.img
[2026-02-08 14:30:45] [backup_1995] SUCCESS: Disk image created
Waiting for disk removal...
(Remove disk to continue with next one)
✓ Disk removed
Enter floppy ID (or 'q' to quit): backup_1995
⚠️ WARNING: Floppy ID 'backup_1995' has already been processed!
Process anyway? (y/N): n
Skipping duplicate ID
Enter floppy ID (or 'q' to quit): q
Session complete. Check logs for details:
Session log: ./floppy_images/session.log
Individual logs: ./floppy_images/<floppy_id>.log
Total processed: 1 disk(s)
ddrescue Mode (--ddrescue flag)
$ sudo ./scripts/floppy-batch.py --ddrescue
============================================================
Floppy Disk Batch Processor
============================================================
Device: /dev/sde
Output directory: ./floppy_images
Session log: ./floppy_images/session.log
Mount point: /mnt/floppy_temp
Imaging tool: ddrescue
============================================================
Enter floppy ID (or 'q' to quit): damaged_disk
Waiting for floppy disk insertion...
(Insert disk now, detection is automatic)
✓ Disk detected (2880 blocks)
Mounting floppy from /dev/sde...
[2026-02-08 14:30:26] [damaged_disk] Successfully mounted
[2026-02-08 14:30:26] [damaged_disk] Found 5 file(s)
[2026-02-08 14:30:26] [damaged_disk] Original volume label: OLDDISK
Unmounting before creating image...
Creating disk image with ddrescue: ./floppy_images/damaged_disk.img
GNU ddrescue 1.27
Press Ctrl-C to interrupt
ipos: 1474 kB, non-trimmed: 0 B, current rate: 49152 B/s
opos: 1474 kB, non-scraped: 0 B, average rate: 47104 B/s
non-tried: 0 B, bad-sector: 0 B, error rate: 0 B/s
rescued: 1474 kB, bad areas: 0, run time: 31s
pct rescued: 100.00%, read errors: 0, remaining time: n/a
time since last successful read: n/a
Finished
[2026-02-08 14:31:01] [damaged_disk] ddrescue image created successfully (1.41 MB)
[2026-02-08 14:31:01] [damaged_disk] SUCCESS: Disk image created
Waiting for disk removal...
✓ Disk removed
Technical Details
Automatic Disk Detection
The script monitors /sys/block/sde/size to detect disk insertion:
- Polls every 0.5 seconds for size changes
- Waits for size to become non-zero (disk inserted)
- Requires 3 consecutive stable readings before proceeding
- Adds 1 second final delay for drive stabilization
- Detects the capacity change events you see in
dmesg
This eliminates the need for manual confirmation and ensures the drive is ready before mounting.
Per-Floppy Logging
Each floppy disk gets its own detailed log file:
- Log file naming:
<floppy_id>.log(e.g.,disk001.log) - Contains: All operations for that specific disk
- Includes: Mount attempts, file listings, imaging output, errors
- ddrescue output: Full verbose output captured when using
--ddrescue - Session log:
session.logtracks overall session progress - Benefits: Easy to review individual disk processing, troubleshoot specific issues
Duplicate Prevention
Processed floppy IDs are tracked in processed_ids.txt:
- Each processed ID is recorded (success or failure)
- On startup, previously processed IDs are loaded
- Warns when attempting to reprocess an ID
- Allows override if intentional (e.g., retry after fixing disk)
- Prevents accidental reprocessing of same disk
Volume Label Preservation
The script preserves the original disk name/label:
Reading the label:
- Uses
dosfslabelto read from the device - Falls back to
blkidif needed - Reads while disk is mounted for reliability
Setting the label:
- dd method: Label automatically preserved in raw copy
- Fallback method: Sets label during
mkfs.msdos -n LABELformatting - FAT12 supports up to 11 characters
- Logged for reference
This preserves the original disk identity in the archived image.
Mounting Strategy
The script tries multiple filesystem types in order:
msdos- MS-DOS FAT filesystemvfat- VFAT (Windows 95+ FAT)ext2- Linux ext2 filesystemauto- Let kernel auto-detect
This ensures compatibility with various floppy disk formats.
Disk Imaging with dd
Command used: dd if=/dev/sde of=<id>.img bs=512 conv=noerror,sync status=progress
bs=512- 512-byte blocks (standard floppy sector size)conv=noerror- Continue on read errorsconv=sync- Pad failed blocks with zerosstatus=progress- Show progress during copy
The image will capture the raw disk structure, including:
- Boot sector
- File allocation table
- Directory entries
- All file data
- Empty space
Disk Imaging with ddrescue (--ddrescue flag)
Command used: ddrescue -v -d -R -r 3 -b 512 /dev/sde <id>.img <id>.map
Flags explained:
-v- Verbose mode (shows detailed progress)-d- Use direct disc access (bypasses OS cache for better hardware error detection)-R- Reverse direction of copying (reads from end to start, useful for damaged media)-r 3- Retry bad sectors up to 3 times-b 512- Block size 512 bytes (standard floppy sector size)- Creates a map file (
.map) tracking which sectors succeeded/failed
Advantages over dd:
- Better error recovery - Multiple retry strategies
- Progress monitoring - Real-time status with detailed statistics
- Rescue maps - Tracks good/bad sectors, can resume interrupted operations
- Optimized for damaged media - Skips bad sectors initially, retries later
- Live output - See exactly what's happening during the copy
Output displayed:
- Current position
- Rescued data size
- Error count
- Average read rate
- Time elapsed/remaining
All output is shown in terminal AND logged to the floppy's log file.
Fallback Method for Damaged Disks
When dd/ddrescue fails (disk too damaged for raw copy), the script automatically creates a separate fallback image to preserve both copies:
Filenames:
- Original raw copy attempt:
<id>.img(may be partial/corrupted) - Fallback file recovery:
<id>_files.img(clean FAT12 with recovered files)
Process:
- Creates empty image:
dd if=/dev/zero of=<id>_files.img bs=1024 count=1440 - Formats as FAT12:
mkfs.msdos -F 12 <id>_files.img(standard floppy format) - Mounts as loop:
losetup -f --show <id>_files.imgto get writable image - Copies files individually: Uses
cp -pto preserve metadata - Logs each file: Shows ✓ for success, ✗ for failures
- Partial success: Succeeds if at least one file copied
- Cleanup: Unmounts loop device and detaches
Benefits:
- Preserves both images: Original raw attempt + clean file recovery
- Recovers readable data from partially damaged disks
- Shows exactly which files failed to copy
- Creates valid FAT12 image with recovered files
- Can analyze the raw image separately for forensics/data recovery
Limitations:
_files.imgdoesn't capture raw disk structure (boot sector, bad sectors, etc.)- Only gets files that can be read through filesystem
- Lost files won't appear in recovered image
Disk Removal Detection
After processing each disk, the script automatically waits for removal:
- Monitors
/sys/block/sde/sizeuntil it returns to 0 - Polls every 0.5 seconds
- Prevents starting next disk while previous one is still in drive
- Ensures clean state between disks
Error Handling
- Mount failures: Logged as WARNING, continues to raw imaging (dd/ddrescue can read without mounting)
- No files (when successfully mounted): Logged and skipped (no image created), ID marked as processed
- Unmount failures: Warning logged, continues to imaging
- Image creation failures: Logged with FAIL status, ID marked as processed
- Unexpected errors: Caught and logged, allows continuation, ID marked as processed
- Always unmounts: Even on error, cleanup is attempted
- Failed IDs tracked: Prevents infinite retry loops on bad disks
File ID Sanitization
Floppy IDs are sanitized to safe filenames by keeping only:
- Alphanumeric characters (a-z, A-Z, 0-9)
- Hyphens (-)
- Underscores (_)
- Periods (.)
Requirements
- Must run as root (sudo)
- USB floppy drive connected and recognized by Linux
- Sufficient disk space for images (~1.44MB per floppy)
- Write permissions in output directory
Dependencies
No external Python dependencies required (uses only standard library).
System requirements:
mountcommandumountcommandddcommandddrescuecommand (optional, for--ddrescueflag - highly recommended for old/damaged disks)losetupcommand (for loop device mounting in fallback mode)mkfs.msdoscommand (for creating FAT filesystems in fallback mode, usually indosfstoolspackage)dosfslabelcommand (for reading/writing volume labels, usually indosfstoolspackage)blkidcommand (for reading volume labels as fallback, usually inutil-linuxpackage)cpcommand- Linux kernel with floppy drive support
Install ddrescue:
# Debian/Ubuntu
sudo apt install gddrescue
# The command is 'ddrescue' (GNU ddrescue), not 'dd_rescue'
Troubleshooting
"Error: This script must be run as root"
- Run with
sudo
"Error: Device /dev/sde does not exist"
- Check USB floppy is connected:
ls -l /dev/sd* - Verify correct device path with
dmesg | tailafter plugging in
"WARNING: Could not mount floppy disk"
- Script will continue with raw disk imaging (dd/ddrescue doesn't need mounting)
- Disk may be corrupted, unformatted, or have unknown filesystem
- Raw image may still contain recoverable data
- If imaging succeeds, you can analyze the .img file with data recovery tools
"No files found on disk - skipping"
- Disk is empty or contains only hidden system files
- This is expected behavior for blank disks
"dd failed, attempting manual file-by-file copy"
- Normal for damaged/worn disks that can't be read as raw device
- Fallback method will recover readable files
- Check log to see which files succeeded (✓) and failed (✗)
- Creates two images:
<id>.img(partial raw) +<id>_files.img(recovered files) - Both images preserved for different recovery approaches
Some files marked with ✗ during manual copy
- Those specific files have read errors (bad sectors)
- Other files on same disk may be fine
- Recovered files are in the .img file
- Consider the disk worn out, don't reuse it
Disk keeps unmounting during image creation
- Normal - script unmounts before dd to ensure consistency
- dd reads from raw device, not mounted filesystem
Automatic detection not working
- Verify
/sys/block/sde/sizeexists (adjust device name if needed) - Check with:
cat /sys/block/sde/sizebefore and after inserting disk - Should show
0when empty,2880when disk inserted - If not working, check dmesg for device name
Script stuck on "Waiting for floppy disk insertion"
- Make sure you insert the disk AFTER seeing this message
- If disk already inserted, remove and reinsert it
- Drive needs to detect the insertion event