#!/bin/sh
set -eu
LOGFILE="/tmp/fat32-recover-$(date +%Y%m%d_%H%M%S).log"
MOUNT_POINT="/mnt/usb"
DEFAULT_ENCODING="en_US.UTF-8"
DEFAULT_CODEPAGE="CP437"
DEVICE=""
ENCODING=""
CODEPAGE=""
trap 'fatal "An unexpected error occurred. Check the log for details."' INT TERM HUP
trap 'cleanup' EXIT
log() {
echo "[*] $(date +%H:%M:%S) $1" | tee -a "$LOGFILE"
}
warn() {
echo "[!] $(date +%H:%M:%S) $1" | tee -a "$LOGFILE" >&2
}
fatal() {
MSG="[✘] $(date +%H:%M:%S) $1"
echo "$MSG" | tee -a "$LOGFILE" >&2
if command -v zenity >/dev/null 2>&1; then
zenity --error --title="FAT32 Recovery Error" --text="$1\n\nLog saved at:\n$LOGFILE"
else
echo "$MSG"
fi
exit 1
}
cleanup() {
if mount | grep -q "$MOUNT_POINT"; then
umount "$MOUNT_POINT" >>"$LOGFILE" 2>&1 || warn "Cleanup: failed to unmount $MOUNT_POINT"
fi
}
ensure_package() {
PKG="$1"
if ! pkg info -e "$PKG"; then
log "Installing missing package: $PKG"
pkg install -y "$PKG" >>"$LOGFILE" 2>&1 || fatal "Failed to install required package: $PKG"
else
log "Verified: $PKG is installed."
fi
}
ensure_package zenity
zenity --info --title="FAT32 Recovery Utility" \
--text="This tool detects and mounts FAT32 USB partitions.\nRecovery is offered for filesystems marked dirty.\n\nLog file: $LOGFILE"
log "Scanning for USB partitions..."
ALL_PARTS=$(sysctl -n kern.disks | tr ' ' '\n' | grep ^da | while read -r disk; do
for part in s1 s2 p1 p2 ""; do
path="/dev/${disk}${part}"
[ "$part" = "" ] && path="/dev/${disk}"
[ -e "$path" ] && echo "$path"
done
done)
[ -z "$ALL_PARTS" ] && fatal "No USB partitions were found. Ensure the USB device is properly inserted."
DEVICE=$(echo "$ALL_PARTS" | zenity --list --title="Select USB Partition" \
--text="Choose a FAT32 partition to scan and mount" \
--column="Device" --width=400 --height=300) || fatal "No partition was selected. Operation cancelled."
log "Selected partition: $DEVICE"
mkdir -p "$MOUNT_POINT"
detect_codepage() {
OUTPUT=$(file -s "$DEVICE" 2>/dev/null || true)
echo "$DEFAULT_CODEPAGE"
}
detect_encoding() {
echo "$DEFAULT_ENCODING"
}
ENCODING=$(detect_encoding)
CODEPAGE=$(detect_codepage)
STATUS_OUTPUT=$(file -s "$DEVICE" 2>/dev/null || echo "Unknown format")
PART_INFO=$(gpart show "$DEVICE" 2>/dev/null || echo "Partition map unavailable")
SUMMARY="Device: $DEVICE\n\nFilesystem: $STATUS_OUTPUT\nEncoding: $ENCODING\nCodepage: $CODEPAGE\n\nPartition Info:\n$PART_INFO\n\nProceed?"
zenity --question --title="Confirm Mount and Scan" \
--width=500 --height=400 --text="$SUMMARY" || fatal "User cancelled before mounting."
log "Unmounting $MOUNT_POINT if needed..."
umount "$MOUNT_POINT" >>"$LOGFILE" 2>/dev/null || true
log "Attempting to mount FAT32 partition..."
if ! mount -t msdosfs -o longnames,-L="$ENCODING",-D="$CODEPAGE" "$DEVICE" "$MOUNT_POINT" >>"$LOGFILE" 2>&1; then
warn "Initial mount failed. Possible dirty bit set or filesystem error."
fi
if mount | grep "$MOUNT_POINT" | grep -q "read-only"; then
zenity --question --title="Filesystem Appears Dirty" \
--text="The filesystem was mounted read-only. This likely means it was not cleanly unmounted.\nWould you like to attempt repair with fsck_msdosfs?" || fatal "Mount read-only, and repair declined."
log "Running fsck_msdosfs..."
fsck_msdosfs -y "$DEVICE" | tee -a "$LOGFILE"
log "Reattempting mount after repair..."
if ! mount -t msdosfs -o longnames,-L="$ENCODING",-D="$CODEPAGE" "$DEVICE" "$MOUNT_POINT" >>"$LOGFILE" 2>&1; then
fatal "Mount failed even after filesystem repair."
fi
fi
zenity --info --title="FAT32 Mounted" \
--text="✅ Successfully mounted:\n$DEVICE\n\nMount point:\n$MOUNT_POINT\n\nLog saved at:\n$LOGFILE"
log "Operation complete. Mounted at $MOUNT_POINT"
exit 0
The above fat32 recover gui.sh
script is a graphical utility developed for GhostBSD and FreeBSD systems to safely detect, inspect, and mount FAT32 formatted USB drives, particularly those marked as dirty due to improper ejection on Windows or Linux systems. Upon execution, the script begins by logging all activity to a timestamped file located in the temporary directory and ensures that required packages, such as Zenity, are installed using the system's package manager. It then queries the system for connected USB storage devices by invoking the sysctl
interface, extracts valid FAT32 partition paths such as /dev/da0s1
or /dev/da1p1
, and presents the user with a graphical selection menu. Once a device is selected, the script retrieves the file system type using the file
command, obtains partition geometry using gpart
, and constructs a detailed status report that includes the selected device, file system summary, mount encoding, codepage, and partition table. This report is presented through a confirmation dialog, allowing the user to approve or decline the operation. If confirmed, the script ensures the mount point exists, unmounts any preexisting mounts at that location, and attempts to mount the selected partition using msdosfs
with options that support long filenames, UTF-8 encoding, and the CP437 codepage. If the file system mounts as read-only, which often indicates the volume is marked as dirty, the script prompts the user for permission to perform file system repair using fsck msdosfs
. Should the user approve, the script executes the repair and retries the mount operation. Upon successful mounting, a final information dialog is shown to confirm the outcome and provide the mount location and the log file path. The script employs structured error handling and cleanup routines to ensure the device is unmounted properly if the operation is interrupted or fails at any point. Throughout the procedure, no changes are made to the USB device unless the user explicitly authorizes repair. All operations are presented through safe and user friendly graphical dialogs, making this utility appropriate for both technical users and those with limited experience in FreeBSD based environments.