Skip to content

Instantly share code, notes, and snippets.

@n8henrie
Forked from Pesticles/gist:d16ad533a09927362a80
Last active May 25, 2021 20:40
Show Gist options
  • Save n8henrie/8d8a9155f93522b45666e3d82a13797c to your computer and use it in GitHub Desktop.
Save n8henrie/8d8a9155f93522b45666e3d82a13797c to your computer and use it in GitHub Desktop.
SD Card image shrinker
#!/bin/bash
######################################################
# sd_shrink.sh
# Usage: sudo bash sd_shrink.sh /dev/DEVICE FILENAME
# Backs up and shrinks DEVICE to FILENAME_YYYYmmdd.img
######################################################
set -euf -o pipefail
BACKUP_DIR=${BACKUP_DIR:-/mnt/n8storage/Tech/Linux}
err() {
(echo >&2 "$0 ERROR: $1")
exit 1
}
USAGE="Usage: sudo bash $0 /dev/DEVICE FILENAME"
if [ -z "${1-}" ]; then
err "$USAGE"
fi
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
echo "$USAGE"
exit
fi
if [ $# -ne 2 ]; then
err "Wrong number of arguments.
Usage: sudo bash $0 /dev/DEVICE FILENAME"
fi
if [ $(id -u) -ne 0 ]; then
err "Must run as root."
fi
if [ -b "$1" ]; then
DEVICE="$1"
else
err "$1 is not a block device"
fi
FILENAME="$2"
IMG="${FILENAME}_$(date "+%Y%m%d")".img
if [ -e "${IMG}" ]; then
err "${IMG} already exists"
else
pushd "${BACKUP_DIR}" > /dev/null
echo "Backing up SD card to ${PWD}/${IMG}"
dd if="${DEVICE}" of="${IMG}" bs=4M status=progress conv=fsync
sync
fi
echo "Shrinking SD card"
# https://gist.github.com/toddtreece/56c16aa06905998d7c94d638cc9cd5fb
P_START=$(fdisk --list --units=sectors "${IMG}" | awk '/Linux/ {gsub("*", ""); print $2}') # Start of 2nd partition in 512 byte sectors
P_SIZE=$(($(fdisk --list --units=sectors "${IMG}" | awk '/Linux/ {gsub("*", ""); print $3}') * 1024)) # Partition size in bytes
modprobe loop
loopdevice="$(losetup -f)"
losetup "${loopdevice}" "${IMG}" -o $(($P_START * 512)) --sizelimit $P_SIZE
fsck -fy "${loopdevice}"
resize2fs -M "${loopdevice}" # Make the filesystem as small as possible
fsck -fy "${loopdevice}"
P_NEWSIZE=$(dumpe2fs "${loopdevice}" 2> /dev/null | awk '/^Block count:/ {print $3}') # In 4k blocks
P_NEWEND=$(($P_START + ($P_NEWSIZE * 8) + 1)) # in 512 byte sectors
losetup -d "${loopdevice}"
echo -e "p\nd\n2\nn\np\n2\n$P_START\n$P_NEWEND\np\nw\n" | fdisk "${IMG}"
I_SIZE=$((($P_NEWEND + 1) * 512)) # New image size in bytes
truncate -s $I_SIZE "${IMG}"
sync
echo "Compressing ${IMG}"
gzip "${IMG}"
echo "Done"
echo "Output file:"
ls -lh "${IMG}".gz
popd > /dev/null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment