Skip to content

Instantly share code, notes, and snippets.

@gammy
Last active December 26, 2022 00:52
Show Gist options
  • Select an option

  • Save gammy/b6299d14559d1150671d to your computer and use it in GitHub Desktop.

Select an option

Save gammy/b6299d14559d1150671d to your computer and use it in GitHub Desktop.
Mount/Read/Write Floppy Emulation USB sticks
#!/usr/bin/env bash
# This is a tool to assist in the usage of floppy disk hardware emulators:
# https://en.wikipedia.org/wiki/Floppy_disk_hardware_emulator
#
# Several of these devices (presumably cheaper ones) don't store
# floppy drives as files on an existing file system, but rather just
# store the raw data with a 96K offset. It renders the USB-stick
# useless for any other purposes.
#
# It also means that you need customized software to access the virtual
# floppy disks. What a cheap way to do it!
#
# Anyhow, with the information provided on Gough Lui's blogpost
# http://goughlui.com/2013/04/24/review-unbranded-1-44mb-usb-100-floppy-emulator/
#
# this script allows you to perform basic operations such as
# - Create or Copy data to a virtual floppy disk
# - Write a floppy disk image to a specific slot (number)
# - Mount any virtual floppy disk image slot
#
# It only uses stock tools such as `dd`, `mkfs.msdos` and `mount`.
# Obtw, the mounting code needs loopback support in your kernel.
#
# By gammy
block_size=1024
block_count=1440
disk_padding=96
deps=(dd mount mkfs.msdos )
for dep in ${deps[@]}; do
which $dep > /dev/null || exit $?
done
floppy_params="bs=${block_size} count=${block_count}"
let fs_limit="$block_size * $block_count"
function usage() {
local me=$(basename $0)
echo "Mount/Read/Write Floppy Emulation USB sticks"
echo
echo " - USE WITH EXTREME CAUTION - "
echo
echo "Usage: $me <mode> [in] [out] [slot]"
echo
echo "Modes:"
echo "new : Create an empty 1.44M disk image in [out]"
echo "copy : Copy file or directory [in] to floppy image [out]"
echo " (runs 'new [out]' if [out] doesn't exist)"
echo "write: Write [in (floppy image)] to [out (usb image)], slot [slot]"
echo "dump : Write [in], [slot] to [out] *TODO*"
echo "mount: Mount [in], [slot] to [out]"
echo
echo "Example:"
echo " $me copy ~/floppy_disk/ disk1.img"
echo " $me write disk1.img /dev/usb3 1"
echo " $me mount /dev/usb3 1 /mnt/fd"
echo
echo "For some interesting information, see"
echo "http://goughlui.com/2013/04/24/review-unbranded-1-44mb-usb-100-floppy-emulator/"
}
function do_new() {
local out="$1"
if [ -z "$out" ]; then
usage
exit 1
fi
dd ${floppy_params} if=/dev/zero of="$out"
mkfs.msdos "$out"
if [ $? = 0 ]; then
du -sk "$out"
fi
}
function do_copy() {
if [ "$UID" != "0" ]; then
echo "Sorry, I need root priveleges to mount an image" >&2
exit 1
fi
local in="$1"
local out="$2"
if [ -z "$in" -o -z "$out" ]; then
usage
exit 1
fi
if [ ! -e "$in" ]; then
echo "\"$in\": doesn't exist" >&2
exit 1
fi
srcsize=$(du -sk "$in" | cut -f 1)
echo "Source size: ${srcsize}K"
if [ $srcsize -ge $block_count ]; then
echo -n "\"$in\": ${srcsize}K: "
echo "won't fit onto \"$out\" ${block_count}" >&2
exit 1
fi
if [ ! -e "$out" ]; then
do_new "$out"
else
echo "Note: \"$out\": already exists"
fi
tmp_mount=$(mktemp --directory)
mount "$out" "$tmp_mount"
ret=$?
if [ "$ret" -ne 0 ]; then
echo "mount \"$out\" \"$tmp_mount\": Failure: $ret" >&2
exit $ret
fi
if [ -d "$in" ]; then
cp -rv "$in/"* "$tmp_mount/"
else
cp -v "$in" "$tmp_mount/"
fi
umount "$tmp_mount"
rm -rf "$tmp_mount"
}
function do_write() {
local in=$1
local out=$2
local slot=$3
if [ -z "$in" -o -z "$out" -o -z "$slot" ]; then
usage
exit 1
fi
if [ ! -e "$in" ]; then
echo "\"$in\": doesn't exist" >&2
exit 1
fi
if [ -e "$out" ]; then
echo "Note: \"$out\": already exists" >&2
fi
case "$slot" in
''|*[!0-9]*)
echo "\"$slot\": Not a number" >&2
exit 1
;;
*)
;;
esac
let offset="(${block_count} + ${disk_padding}) * $slot"
echo "Copy \"$in\" to \"$out\", slot $slot"
echo dd ${floppy_params} seek="$offset" if="$in" of="$out"
dd ${floppy_params} seek="$offset" if="$in" of="$out"
}
function do_mount() {
if [ "$UID" != "0" ]; then
echo "Sorry, I need root priveleges to mount an image" >&2
exit 1
fi
local in=$1
local out=$2
local slot=$3
if [ -z "$in" -o -z "$out" -o -z "$slot" ]; then
usage
exit 1
fi
if [ ! -e "$in" ]; then
echo "\"$in\": doesn't exist" >&2
exit 1
fi
case "$slot" in
''|*[!0-9]*)
echo "\"$slot\": Not a number" >&2
exit 1
;;
*)
;;
esac
let offset="$block_size * ($block_count + $disk_padding) * $slot"
echo mount -o loop,offset=${offset},sizelimit=${fs_limit} -t msdos "$in" "$out"
mount -o loop,offset=${offset},sizelimit=${fs_limit} \
-t msdos \
"$in" \
"$out"
ret="$?"
if [ "$ret" = "32" ]; then
echo -n "Failed to mount \"$in\", slot $slot. "
echo "Does that slot exist?" >&2
return $ret
fi
}
mode=$1
shift
case "$mode" in
"new")
do_new "$1"
;;
"copy")
do_copy "$1" "$2"
;;
"write")
do_write "$1" "$2" "$3"
;;
"mount")
do_mount "$1" "$3" "$2"
;;
*)
usage
exit 1
esac
echo "Finished"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment