From f867503a5771eb456345ce2879956fc58e422e61 Mon Sep 17 00:00:00 2001 From: crowetic Date: Thu, 3 Apr 2025 02:40:07 +0000 Subject: [PATCH] Upload files to "/" --- auto-shrink-compress-img.sh | 229 +++++++++++++++++++++++++ create-image-sdcard-resize-optional.sh | 75 ++++++++ 2 files changed, 304 insertions(+) create mode 100644 auto-shrink-compress-img.sh create mode 100644 create-image-sdcard-resize-optional.sh diff --git a/auto-shrink-compress-img.sh b/auto-shrink-compress-img.sh new file mode 100644 index 0000000..e594454 --- /dev/null +++ b/auto-shrink-compress-img.sh @@ -0,0 +1,229 @@ +#!/bin/bash +set -e + +SECTOR_SIZE=512 +PADDING_MB=4 +IMAGE="" +RESIZED_IMAGE="" +COMPRESSED_NAME="" + +echo "==== ๐Ÿ” Smart SD Image Shrinker ====" + +# === Step 1: Find .img files === +mapfile -t IMAGES < <(find . -maxdepth 1 -type f -name "*.img" | sort) + +if [ ${#IMAGES[@]} -eq 0 ]; then + echo "โŒ No .img files found in the current directory." + exit 1 +fi + +echo "" +echo "๐Ÿ“‚ Found the following .img files:" +for i in "${!IMAGES[@]}"; do + printf " [%d] %s\n" "$((i+1))" "${IMAGES[$i]}" +done + +echo "" +read -p "๐Ÿ‘‰ Enter the number of the image you want to shrink: " SELECTION + +if ! [[ "$SELECTION" =~ ^[0-9]+$ ]] || [ "$SELECTION" -lt 1 ] || [ "$SELECTION" -gt "${#IMAGES[@]}" ]; then + echo "โŒ Invalid selection." + exit 1 +fi + +IMAGE="${IMAGES[$((SELECTION-1))]}" +BASENAME=$(basename "$IMAGE") +echo "โœ… Selected: $IMAGE" +echo "" + +# === Step 2: Select auto or manual sizing === +echo "๐Ÿ“ Choose target size mode:" +echo " [1] Auto-select smallest SD card (adds 2GB headroom)" +echo " [2] Choose target SD card size manually" +read -p "๐Ÿ‘‰ Enter your choice [1-2]: " SIZE_MODE + +if [[ "$SIZE_MODE" != "1" && "$SIZE_MODE" != "2" ]]; then + echo "โŒ Invalid selection." + exit 1 +fi + +# === Step 3: Auto-fix GPT if needed === +echo "[*] Pre-checking GPT for leftover space issues..." +echo -e "w\ny\n" | sudo gdisk "$IMAGE" >/dev/null 2>&1 || true + +# === Step 4: Attach image to loop device === +echo "๐Ÿ“Œ Attaching image to loop device..." +LOOP_DEV=$(sudo losetup --show -Pf "$IMAGE") + +# === Step 5: Detect rootfs === +PARTS=$(lsblk -nrpo NAME "$LOOP_DEV" | grep -E "$LOOP_DEV"p) +ROOT_PART=$(for P in $PARTS; do lsblk -bno SIZE "$P" | awk -v p="$P" '{print $1, p}'; done | sort -nr | head -n1 | awk '{print $2}') + +if [ -z "$ROOT_PART" ]; then + echo "โŒ Error: Couldn't detect root partition." + sudo losetup -d "$LOOP_DEV" + exit 1 +fi + +PART_NUM=$(basename "$ROOT_PART" | grep -o '[0-9]*$') +echo "๐Ÿ” Detected rootfs: $ROOT_PART (Partition #$PART_NUM)" + +# === Step 6: Unmount if mounted === +sudo umount "$ROOT_PART" 2>/dev/null || true + +# === Step 7: Determine used space + headroom === +USED_MB=$(sudo df -m "$ROOT_PART" | awk 'NR==2 {print $3}') +REQUIRED_MB=$(( USED_MB + 2048 )) + +# === Define known SD card sizes (actual usable MB) === +declare -A SD_SIZES +SD_SIZES=( + ["8GB"]=6900 + ["16GB"]=13500 + ["32GB"]=29000 + ["64GB"]=59000 + ["128GB"]=119000 +) + +# === Determine final TARGET_SIZE_MB === +if [ "$SIZE_MODE" == "1" ]; then + echo "๐Ÿง  Auto-selecting smallest SD card size to fit $REQUIRED_MB MB..." + + for label in 8GB 16GB 32GB 64GB 128GB; do + if [ "$REQUIRED_MB" -le "${SD_SIZES[$label]}" ]; then + TARGET_SIZE_MB=${SD_SIZES[$label]} + SIZE_LABEL=$label + echo "โœ… Selected size: $SIZE_LABEL (${TARGET_SIZE_MB} MB)" + break + fi + done + + if [ -z "$SIZE_LABEL" ]; then + echo "โŒ No supported SD size large enough. Required: $REQUIRED_MB MB" + sudo losetup -d "$LOOP_DEV" + exit 1 + fi + +else + echo "" + echo "๐Ÿ“ Choose target SD card size:" + OPTIONS=("8GB" "16GB" "32GB" "64GB" "128GB") + for i in "${!OPTIONS[@]}"; do + printf " [%d] %s\n" "$((i+1))" "${OPTIONS[$i]}" + done + read -p "๐Ÿ‘‰ Enter your choice [1-5]: " SIZE_CHOICE + + if ! [[ "$SIZE_CHOICE" =~ ^[1-5]$ ]]; then + echo "โŒ Invalid selection." + sudo losetup -d "$LOOP_DEV" + exit 1 + fi + + SIZE_LABEL=${OPTIONS[$((SIZE_CHOICE-1))]} + TARGET_SIZE_MB=${SD_SIZES[$SIZE_LABEL]} + + if [ "$REQUIRED_MB" -gt "$TARGET_SIZE_MB" ]; then + echo "โš ๏ธ $SIZE_LABEL is too small to hold this data (need $REQUIRED_MB MB)" + echo "๐Ÿ” Auto-selecting next size up..." + + FOUND=0 + for label in 16GB 32GB 64GB 128GB; do + if [ "$REQUIRED_MB" -le "${SD_SIZES[$label]}" ]; then + TARGET_SIZE_MB=${SD_SIZES[$label]} + SIZE_LABEL=$label + echo "โœ… Switched to: $SIZE_LABEL (${TARGET_SIZE_MB} MB)" + FOUND=1 + break + fi + done + + if [ "$FOUND" -eq 0 ]; then + echo "โŒ No SD size large enough. Required: $REQUIRED_MB MB" + sudo losetup -d "$LOOP_DEV" + exit 1 + fi + else + echo "โœ… Selected target: $SIZE_LABEL (${TARGET_SIZE_MB} MB)" + fi +fi + +# === Step 8: fsck and resize === +echo "๐Ÿ”ง Running fsck and shrinking rootfs..." +sudo e2fsck -fy "$ROOT_PART" | tee fsck.log +if grep -q "FILE SYSTEM WAS MODIFIED" fsck.log; then + echo "๐Ÿ” FS was modified. Re-checking..." + sudo e2fsck -fy "$ROOT_PART" +fi +rm -f fsck.log +sudo resize2fs "$ROOT_PART" "${TARGET_SIZE_MB}M" + +# === Step 9: Resize partition === +START_SECTOR=$(sudo parted -s "$IMAGE" unit s print | grep "^ $PART_NUM" | awk '{print $2}' | sed 's/s//') +TARGET_SECTORS=$((TARGET_SIZE_MB * 1024 * 1024 / SECTOR_SIZE)) +END_SECTOR=$((START_SECTOR + TARGET_SECTORS - 1)) + +PART_TYPE=$(sudo parted -s "$IMAGE" print | grep "Partition Table" | awk '{print $3}') +echo "๐Ÿง  Partition table type: $PART_TYPE" + +if [[ "$PART_TYPE" == "msdos" ]]; then + echo "๐Ÿ”ง Updating MBR partition..." + PART_DEV="./${BASENAME}${PART_NUM}" + echo "๐Ÿงช Looking for partition entry named: $PART_DEV" + echo "๐Ÿ“„ sfdisk --dump preview:" + sudo sfdisk --dump "$IMAGE" | grep "$PART_DEV" + TEMP_SFDISK="temp-sfdisk-edit.txt" + + echo "๐Ÿ“„ Updating partition entry for: $PART_DEV" + + sudo sfdisk --dump "$IMAGE" | awk -v dev="$PART_DEV" -v start="$START_SECTOR" -v end="$END_SECTOR" ' + BEGIN { updated = 0 } + { + if ($1 == dev) { + size = end - start + 1 + print $1 " : start=" start ", size=" size ", type=83" + updated = 1 + } else { + print $0 + } + } + END { + if (updated == 0) { + print "โŒ Failed to update partition: entry not found for " dev > "/dev/stderr" + exit 1 + } + }' > "$TEMP_SFDISK" + + sudo sfdisk "$IMAGE" < "$TEMP_SFDISK" + rm -f "$TEMP_SFDISK" + +elif [[ "$PART_TYPE" == "gpt" ]]; then + echo "๐Ÿ”ง Updating GPT partition..." + sudo sgdisk --delete=$PART_NUM "$IMAGE" + sudo sgdisk --new=$PART_NUM:$START_SECTOR:$END_SECTOR "$IMAGE" +else + echo "โŒ Unknown partition type: $PART_TYPE" + sudo losetup -d "$LOOP_DEV" + exit 1 +fi + +# === Step 10: Detach + truncate resized image === +sudo losetup -d "$LOOP_DEV" +TRUNC_SIZE=$(( (END_SECTOR + (PADDING_MB * 1024 * 1024 / SECTOR_SIZE)) * SECTOR_SIZE )) +RESIZED_IMAGE="resized-${SIZE_LABEL}-${BASENAME}" +echo "โœ‚๏ธ Creating resized image: $RESIZED_IMAGE" +dd if="$IMAGE" of="$RESIZED_IMAGE" bs=1M count=$((TRUNC_SIZE / 1024 / 1024)) status=progress + +# === Step 11: Compress === +echo "๐Ÿ“ฆ Compressing to .xz..." +xz -T0 -9 "$RESIZED_IMAGE" +echo "" +echo "๐Ÿ” Verifying compressed image..." +if xz -t "${RESIZED_IMAGE}.xz"; then + echo "โœ… Compression verified!" +else + echo "โŒ Compression failed! The .xz file may be corrupted." + exit 1 +fi +echo "" +echo "โœ… Done! Output: ${RESIZED_IMAGE}.xz" + diff --git a/create-image-sdcard-resize-optional.sh b/create-image-sdcard-resize-optional.sh new file mode 100644 index 0000000..4b00240 --- /dev/null +++ b/create-image-sdcard-resize-optional.sh @@ -0,0 +1,75 @@ +#!/bin/bash +set -e + +RESIZE_SCRIPT="./auto-shrink-compress-img.sh" + +echo "==== ๐Ÿง  SD Card Disk Imager + Auto Resize ====" + +# === Step 1: Detect likely SD card devices === +echo "" +echo "๐Ÿ“ฆ Scanning for removable storage devices..." +mapfile -t DISKS < <(lsblk -dpno NAME,MODEL,SIZE,RM | awk '$4 == 1 { print $1 }') + +if [ ${#DISKS[@]} -eq 0 ]; then + echo "โŒ No removable (likely SD card) devices found!" + exit 1 +fi + +echo "" +echo "๐Ÿ“‚ Found the following removable block devices:" +for i in "${!DISKS[@]}"; do + disk_info=$(lsblk -dno NAME,MODEL,SIZE "${DISKS[$i]}") + printf " [%d] %s\n" "$((i+1))" "$disk_info" +done + +echo "" +read -p "๐Ÿ‘‰ Enter the number of the disk to back up: " SELECTION + +if ! [[ "$SELECTION" =~ ^[0-9]+$ ]] || [ "$SELECTION" -lt 1 ] || [ "$SELECTION" -gt "${#DISKS[@]}" ]; then + echo "โŒ Invalid selection." + exit 1 +fi + +DISK="${DISKS[$((SELECTION-1))]}" +echo "โœ… Selected disk: $DISK" +echo "" + +# === Step 2: Ask for image filename === +read -p "๐Ÿ’พ Enter a name for the output image file (no extension): " IMG_NAME +IMG_FILE="${IMG_NAME}.img" + +if [ -f "$IMG_FILE" ]; then + echo "โš ๏ธ File '$IMG_FILE' already exists! Please choose a different name." + exit 1 +fi + +echo "" +echo "๐Ÿ“ธ Creating disk image from $DISK..." +sudo dd if="$DISK" of="$IMG_FILE" bs=4M status=progress conv=fsync + +echo "" +echo "โœ… Disk image created: $IMG_FILE" + +# === Step 3: Ask if user wants to auto-shrink === +echo "" +if [ ! -f "$RESIZE_SCRIPT" ]; then + echo "โš ๏ธ Resize script '$RESIZE_SCRIPT' not found! Skipping auto-shrink." + exit 0 +fi + +echo "โณ Would you like to resize & compress this image using:" +echo " $RESIZE_SCRIPT" +echo "" +echo "It will auto-run in 30 seconds if no answer is given." +read -t 30 -p "Type 'n' to skip or press [Enter] to run: " ANSWER + +if [[ "$ANSWER" =~ ^[Nn]$ ]]; then + echo "๐Ÿšซ Skipping resize/compression." + exit 0 +fi + +# === Step 4: Run the shrink script === +echo "" +echo "๐Ÿš€ Running auto-shrink script..." +bash "$RESIZE_SCRIPT" +