diff --git a/README.md b/README.md index abc6bfc..a54bc0a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ using multiple cores is supported. ## Usage ## ``` -Usage: $0 [-adhrsvzZ] imagefile.img [newimagefile.img] +Usage: $0 [-adhrsvzZn] imagefile.img [newimagefile.img] -s Don't expand filesystem when image is booted the first time -v Be verbose @@ -17,6 +17,7 @@ Usage: $0 [-adhrsvzZ] imagefile.img [newimagefile.img] -Z Compress image after shrinking with xz -a Compress image in parallel using multiple cores -d Write debug messages in a debug log file + -n Accept an input that is not a file (e.g. a tf card) ``` If you specify the `newimagefile.img` parameter, the script will make a copy of `imagefile.img` and work off that. You will need enough space to make a full copy of the image to use that option. @@ -28,6 +29,7 @@ If you specify the `newimagefile.img` parameter, the script will make a copy of * `-Z` will compress the image after shrinking using xz. `.xz` extension will be added to the filename. * `-a` will use option -f9 for pigz and option -T0 for xz and compress in parallel. * `-d` will create a logfile `pishrink.log` which may help for problem analysis. +* `-n` will shrink the file system of a tfcard, and create an image file from that if `newimagefile.img` is specified. Default options for compressors can be overwritten by defining PISHRINK_GZIP or PSHRINK_XZ environment variables for gzip and xz. @@ -48,10 +50,10 @@ chmod +x pishrink.sh sudo mv pishrink.sh /usr/local/bin ``` -## Example ## +## Example 1 ## ```bash -[user@localhost PiShrink]$ sudo pishrink.sh pi.img +sudo pishrink.sh pi.img e2fsck 1.42.9 (28-Dec-2013) Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure @@ -73,6 +75,28 @@ The filesystem on /dev/loop1 is now 773603 blocks long. Shrunk pi.img from 30G to 3.1G ``` +## Example 2 ## + +```bash +sudo pishrink.sh -n /dev/sdb pi.img +pishrink.sh v0.1.3 +pishrink.sh: Gathering data ... + +pishrink.sh: Checking filesystem ... +rootfs: 69602/155648 files (0.4% non-contiguous), 457517/599771 blocks +resize2fs 1.46.5 (30-Dec-2021) +pishrink.sh: Shrinking filesystem ... +resize2fs 1.46.5 (30-Dec-2021) +Resizing the filesystem on /dev/sdb2 to 597213 (4k) blocks. +The filesystem on /dev/sdb2 is now 597213 (4k) blocks long. + +pishrink.sh: Creating image ... +5310185+0 records in +5310185+0 records out +2718814720 bytes (2.7 GB, 2.5 GiB) copied, 294.339 s, 9.2 MB/s +pishrink.sh: Shrunk pi.img from 8, to 2.6G ... +``` + ## Contributing ## If you find a bug please create an issue for it. If you would like a new feature added, you can create an issue for it but I can't promise that I will get to it. diff --git a/pishrink.sh b/pishrink.sh index f16af49..4699b62 100755 --- a/pishrink.sh +++ b/pishrink.sh @@ -165,7 +165,7 @@ EOF1 help() { local help read -r -d '' help << EOM -Usage: $0 [-adhrsvzZ] imagefile.img [newimagefile.img] +Usage: $0 [-adhrsvzZn] imagefile.img [newimagefile.img] -s Don't expand filesystem when image is booted the first time -v Be verbose @@ -174,6 +174,7 @@ Usage: $0 [-adhrsvzZ] imagefile.img [newimagefile.img] -Z Compress image after shrinking with xz -a Compress image in parallel using multiple cores -d Write debug messages in a debug log file + -n Accept an input that is not a file (e.g. a tf card) EOM echo "$help" exit 1 @@ -185,8 +186,9 @@ repair=false parallel=false verbose=false ziptool="" +notfile=false -while getopts ":adhrsvzZ" opt; do +while getopts ":adhrsvzZn" opt; do case "${opt}" in a) parallel=true;; d) debug=true;; @@ -196,6 +198,7 @@ while getopts ":adhrsvzZ" opt; do v) verbose=true;; z) ziptool="gzip";; Z) ziptool="xz";; + n) notfile=true;; *) help;; esac done @@ -219,10 +222,14 @@ if [[ -z "$img" ]]; then help fi -if [[ ! -f "$img" ]]; then - error $LINENO "$img is not a file..." - exit 2 +if [ "$notfile" = false ]; then + echo "$notfile" + if [[ ! -f "$img" ]]; then + error $LINENO "$img is not a file..." + exit 2 + fi fi + if (( EUID != 0 )); then error $LINENO "You need to be running as root." exit 3 @@ -261,19 +268,21 @@ done #Copy to new file if requested if [ -n "$2" ]; then - f="$2" - if [[ -n $ziptool && "${f##*.}" == "${ZIPEXTENSIONS[$ziptool]}" ]]; then # remove zip extension if zip requested because zip tool will complain about extension - f="${f%.*}" - fi - info "Copying $1 to $f..." - cp --reflink=auto --sparse=always "$1" "$f" - if (( $? != 0 )); then - error $LINENO "Could not copy file..." - exit 5 - fi - old_owner=$(stat -c %u:%g "$1") - chown "$old_owner" "$f" - img="$f" + if [ "$notfile" = false ]; then #Skip copy if input is device + f="$2" + if [[ -n $ziptool && "${f##*.}" == "${ZIPEXTENSIONS[$ziptool]}" ]]; then # remove zip extension if zip requested because zip tool will complain about extension + f="${f%.*}" + fi + info "Copying $1 to $f..." + cp --reflink=auto --sparse=always "$1" "$f" + if (( $? != 0 )); then + error $LINENO "Could not copy file..." + exit 5 + fi + old_owner=$(stat -c %u:%g "$1") + chown "$old_owner" "$f" + img="$f" + fi fi # cleanup at script exit @@ -292,17 +301,21 @@ fi partnum="$(echo "$parted_output" | tail -n 1 | cut -d ':' -f 1)" partstart="$(echo "$parted_output" | tail -n 1 | cut -d ':' -f 2 | tr -d 'B')" if [ -z "$(parted -s "$img" unit B print | grep "$partstart" | grep logical)" ]; then - parttype="primary" + parttype="primary" else - parttype="logical" + parttype="logical" +fi +if [ "$notfile" = false ]; then + loopback="$(losetup -f --show -o "$partstart" "$img")" +else + loopback=""$img""2"" fi -loopback="$(losetup -f --show -o "$partstart" "$img")" tune2fs_output="$(tune2fs -l "$loopback")" rc=$? if (( $rc )); then - echo "$tune2fs_output" - error $LINENO "tune2fs failed. Unable to shrink this type of image" - exit 7 + echo "$tune2fs_output" + error $LINENO "tune2fs failed. Unable to shrink this type of image" + exit 7 fi currentsize="$(echo "$tune2fs_output" | grep '^Block count:' | tr -d ' ' | cut -d ':' -f 2)" @@ -378,21 +391,37 @@ if (( $rc )); then fi #Truncate the file -info "Shrinking image" -endresult=$(parted -ms "$img" unit B print free) -rc=$? -if (( $rc )); then - error $LINENO "parted failed with rc $rc" - exit 15 -fi +if [ "$notfile" = false ]; then + info "Shrinking image" + endresult=$(parted -ms "$img" unit B print free) + rc=$? + if (( $rc )); then + error $LINENO "parted failed with rc $rc" + exit 15 + fi -endresult=$(tail -1 <<< "$endresult" | cut -d ':' -f 2 | tr -d 'B') -logVariables $LINENO endresult -truncate -s "$endresult" "$img" -rc=$? -if (( $rc )); then - error $LINENO "trunate failed with rc $rc" - exit 16 + endresult=$(tail -1 <<< "$endresult" | cut -d ':' -f 2 | tr -d 'B') + logVariables $LINENO endresult + truncate -s "$endresult" "$img" + rc=$? + if (( $rc )); then + error $LINENO "trunate failed with rc $rc" + exit 16 + fi +else #Skip truncate if input is device + if [ -n "$2" ]; then + target="$2" + info "Creating image" + fdiskresult=$(fdisk -l "$img") + count=$(tail -1 <<< "$fdiskresult" | tr -s ' ' | cut -d ' ' -f 3) + bs=$(head -3 <<< "$fdiskresult" | tail -1 | tr -s ' ' | rev | cut -d ' ' -f 2 | rev) + count=$(expr "$count" + 1) + dd if="$img" of="$target" bs="$bs" count="$count" + img="$target" + else + info "File system shrinked from $beforesize to $aftersize, no image created" + exit 0 + fi fi # handle compression