Advertisement
zmatt

shrink-image

Oct 6th, 2021 (edited)
30
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 1.90 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. set -e
  4. shopt -s lastpipe extglob
  5. set -o pipefail
  6.  
  7. die() {
  8.     echo "$@" >&2
  9.     exit 1
  10. }
  11.  
  12. [[ $# -ge 1 && $# -le 2 ]] || die "Usage: ${BASH_SOURCE} source.img [destination.img]"
  13.  
  14. image="$1"
  15. [[ -f "$image" ]] || die "File not found: $image"
  16. if [[ $# -ge 2 ]]; then
  17.     newimage="$2"
  18. else
  19.     # remove suffix indicating image size
  20.     if [[ "$image" == *-[1-9]gb.img ]]; then
  21.         newimage="${image%-[1-9]gb.img}.img"
  22.     else
  23.         newimage="$image"
  24.     fi
  25. fi
  26. [[ "$newimage" == "$image" || ! -f "$newimage" ]] || die "File exists: $newimage"
  27.  
  28. # determine start of rootfs partition
  29. /sbin/sfdisk --dump /dev/stdin <"$image" | tail -n 1 | {
  30.     read -rd,
  31.     [[ "$REPLY" == '/dev/stdin1 : start='* ]] \
  32.         || die "Not a single-partition image"
  33.     start="${REPLY##*=}"
  34.     (( start % 8 == 0 )) || die "Invalid partition start: $start"
  35.     start=$(( start / 2 ))K
  36. }
  37.  
  38. # rename image if requested
  39. if [[ "$newimage" != "$image" ]]; then
  40.     mv "$image" "$newimage"
  41.     image="$newimage"
  42. fi
  43.  
  44. # split off the part before the rootfs partition (partition table, bootloader)
  45. head -c $start "$image" >"$image.header"
  46. fallocate -c -l $start "$image"
  47.  
  48. # shrink filesystem to minimum size
  49. /sbin/e2fsck -f -p "$image" || [[ $? == 1 ]]
  50. /sbin/resize2fs -M "$image"
  51.  
  52. # determine size of filesystem
  53. declare -A info
  54. /sbin/dumpe2fs -h "$image" 2>/dev/null | grep -P ': *\d+$' | \
  55.     while IFS=: read -r k v; do
  56.         info["${k// /_}"]="${v##*( )}"
  57.     done
  58. size=$(( ${info[Block_size]:?} * ${info[Block_count]:?} / 1024 ))K
  59.  
  60. # truncate image file to filesystem size
  61. truncate --no-create --size=$size "$image"
  62.  
  63. # reinsert the stuff before the rootfs partition (partition table, bootloader)
  64. fallocate -i -l $start "$image"
  65. cat "$image.header" 1<>"$image"
  66. rm "$image.header"
  67.  
  68. # update partition table to match new filesystem size
  69. echo ",$size" | /sbin/sfdisk -N 1 "$image"
  70.  
  71. # all done!  report image name and size
  72. echo "$image  ($start + $size)"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement