#!/usr/bin/env bash set -uo pipefail DEV="/dev/sdb" BOOT="${DEV}1" ROOT="${DEV}2" LOG="$HOME/microsd-test-$(date +%Y%m%d-%H%M%S).log" if [[ $EUID -ne 0 ]]; then echo "Run this script with sudo:" echo " sudo $0" exit 1 fi # If invoked with sudo, save the logfile in the real user's home. if [[ -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]]; then USER_HOME="$(getent passwd "$SUDO_USER" | cut -d: -f6)" LOG="$USER_HOME/microsd-test-$(date +%Y%m%d-%H%M%S).log" fi exec > >(tee -a "$LOG") 2>&1 echo "======================================================" echo " Raspberry Pi microSD diagnostic" echo "======================================================" echo echo "Device: $DEV" echo "Log: $LOG" echo # ------------------------------------------------------- # SAFETY CHECKS # ------------------------------------------------------- if [[ ! -b "$DEV" ]]; then echo "ERROR: $DEV does not exist." exit 1 fi ROOTDEV="$(findmnt -n -o SOURCE / | sed -E 's/p?[0-9]+$//')" if [[ "$ROOTDEV" == "$DEV" ]]; then echo "REFUSING TO CONTINUE." echo "$DEV appears to contain the currently running OS." exit 1 fi echo "Detected device:" lsblk -o NAME,PATH,SIZE,RM,RO,TYPE,FSTYPE,LABEL,MODEL,MOUNTPOINTS "$DEV" echo echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo " Verify that THIS is your 238 GB microSD card:" echo lsblk -d -o NAME,SIZE,RM,MODEL,SERIAL "$DEV" echo echo " This script performs READ-ONLY diagnostics." echo " It WILL NOT format or overwrite the card." echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo read -rp "Type YES to test $DEV: " CONFIRM if [[ "$CONFIRM" != "YES" ]]; then echo "Cancelled." exit 1 fi echo echo "======================================================" echo " 1. Unmounting SD partitions" echo "======================================================" while read -r PART MOUNTPOINT; do [[ -z "$MOUNTPOINT" ]] && continue echo "Unmounting $PART from $MOUNTPOINT..." umount "$PART" || { echo "ERROR: Could not unmount $PART" exit 1 } done < <(lsblk -nrpo NAME,MOUNTPOINT "$DEV") sync echo lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINTS "$DEV" echo echo "======================================================" echo " 2. Checking kernel/device information" echo "======================================================" udevadm info --query=property --name="$DEV" 2>/dev/null | grep -E 'ID_MODEL=|ID_VENDOR=|ID_SERIAL=|ID_BUS=|ID_DRIVE_FLASH|ID_DRIVE_REMOVABLE' || true echo echo "Partition table:" fdisk -l "$DEV" echo echo "======================================================" echo " 3. FAT boot partition filesystem check" echo "======================================================" if [[ -b "$BOOT" ]]; then echo "Running READ-ONLY FAT check on $BOOT..." echo fsck.vfat -n -v "$BOOT" FAT_RESULT=$? echo echo "fsck.vfat exit code: $FAT_RESULT" else echo "WARNING: $BOOT does not exist." FAT_RESULT=99 fi echo echo "======================================================" echo " 4. ext4 root partition filesystem check" echo "======================================================" if [[ -b "$ROOT" ]]; then echo "Running READ-ONLY forced ext4 check on $ROOT..." echo e2fsck -f -n -v "$ROOT" EXT_RESULT=$? echo echo "e2fsck exit code: $EXT_RESULT" else echo "WARNING: $ROOT does not exist." EXT_RESULT=99 fi echo echo "======================================================" echo " 5. Full physical READ scan of microSD" echo "======================================================" echo echo "This reads the ENTIRE ~238 GiB card." echo "Nothing will be written." echo echo "This can take a while depending on the USB adapter." echo START_TIME=$(date +%s) # -s = progress # -v = verbose summary # -b 4096 = 4 KiB blocks # # IMPORTANT: no -w or -n flags are used. # This is read-only. badblocks -s -v -b 4096 "$DEV" BADBLOCK_RESULT=$? END_TIME=$(date +%s) ELAPSED=$((END_TIME - START_TIME)) echo echo "badblocks exit code: $BADBLOCK_RESULT" printf "Physical scan duration: %02d:%02d:%02d\n" \ $((ELAPSED / 3600)) \ $(((ELAPSED % 3600) / 60)) \ $((ELAPSED % 60)) echo echo "======================================================" echo " 6. Looking for USB / SD / I/O errors in kernel log" echo "======================================================" dmesg --color=never | grep -Ei \ 'sdb|usb|uas|scsi|mmc|I/O error|buffer I/O|medium error|sense key|reset|timeout|CRC|failed command' | tail -n 150 || true echo echo "======================================================" echo " RESULTS" echo "======================================================" echo printf "%-30s %s\n" "FAT boot filesystem:" "$FAT_RESULT" printf "%-30s %s\n" "ext4 root filesystem:" "$EXT_RESULT" printf "%-30s %s\n" "physical read scan:" "$BADBLOCK_RESULT" echo if [[ "$BADBLOCK_RESULT" -eq 0 ]]; then echo "[PASS] Full physical card read completed." else echo "[FAIL] Physical read scan reported a problem." fi echo if [[ "$FAT_RESULT" -eq 0 ]]; then echo "[PASS] bootfs FAT filesystem appears clean." else echo "[WARN] bootfs filesystem reported errors or inconsistencies." fi if [[ "$EXT_RESULT" -eq 0 ]]; then echo "[PASS] rootfs ext4 filesystem appears clean." else echo "[WARN] rootfs filesystem reported errors or inconsistencies." fi echo echo "Log saved to:" echo "$LOG" if [[ -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]]; then chown "$SUDO_USER":"$SUDO_USER" "$LOG" 2>/dev/null || true fi echo echo "NO DATA WAS INTENTIONALLY WRITTEN TO THE MICROSD."