From 36d0e4ca0930e1c9c8fb51d2763efdd776445c9b Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Sun, 19 Nov 2023 02:00:35 +0100
Subject: [PATCH 01/23] Update shrink-backup
version update and fix for arch
---
shrink-backup | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/shrink-backup b/shrink-backup
index 980d048..f917bce 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
#
# shrink-backup
-# version 0.9.4
+# version 0.9.5-beta
# backup tool for backing up and updating .img files with autoexpansion on various operating systems
#
# This program is free software: you can redistribute it and/or modify
@@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
-# 10/2023
+# 11/2023
# Marcus Johansson
# https://github.com/UnconnectedBedna/shrink-backup
##############################################################################
@@ -884,7 +884,7 @@ function do_backup() {
echo "# New img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
echo "# Difference: $(( ADDED_SPACE / 1024 / 1024 ))MB"
else
- echo "# Used space on root: $(( $(df / --output=used | tail -1) / 1024 ))MB"
+ echo "# Estemated root usage: $(( $(df / --output=used | tail -1) / 1024 ))MB"
echo "# Total img size: $(( IMG_SIZE / 1024 / 1024 ))MB"
fi
echo '##############################################################################'
@@ -1130,11 +1130,12 @@ EOF
debug 'DEBUG' 'Creating expansion script ${TMP_DIR}/expand-fs.sh'
cat << EOF2 > "${TMP_DIR}/expand-fs.sh"
#!/usr/bin/bash
-LOCAL_DEV_MAJ=\$(lsblk -lpo mountpoint,maj:min,type,path | grep '/ ' | awk '{print \$2}' | cut -d : -f 1)
-LOCAL_ROOT_PARTN=\$(lsblk -lpo mountpoint,maj:min,type,path | grep '/ ' | awk '{print \$2}' | cut -d : -f 2)
-LOCAL_DEV_PATH=\$(lsblk -lpo maj:min,type,path | grep "\$LOCAL_DEV_MAJ" | grep 'disk' | awk '{print \$3}')
+LOCAL_DEV_PTUUID=\$(lsblk -lpo mountpoint,ptuuid | grep '/ ' | awk '{print \$2}')
+LOCAL_DEV_PATH=\$(lsblk -lpo ptuuid,type,path | grep "\$LOCAL_DEV_PTUUID" | grep 'disk' | awk '{print \$3}')
+LOCAL_ROOT_PARTN=\$(parted -sm "\$LOCAL_DEV_PATH" print | tail -1 | cut -d : -f 1)
LOCAL_DEV_ROOT_PATH=\$(lsblk -lpo mountpoint,path | grep '/ ' | awk '{print \$2}')
-LOCAL_ROOT_START=\$(fdisk --bytes -lo start "\$LOCAL_DEV_PATH" | tail -1)
+LOCAL_ROOT_START=\$(fdisk -lo start "\$LOCAL_DEV_PATH" | tail -1 | awk '{print \$1}') # blocks, 512B block size
+LOCAL_ROOT_START=\$(( LOCAL_ROOT_START * 512 )) # bytes
sfdisk --delete "\$LOCAL_DEV_PATH" "\$LOCAL_ROOT_PARTN"
parted -s -a none "\$LOCAL_DEV_PATH" unit B mkpart primary ext4 "\$LOCAL_ROOT_START" 100%
@@ -1173,9 +1174,6 @@ function print_result() {
echo "## $IMG_FILE is ${AFTER_SIZE}MB with $(( ADDED_SPACE / 1024 / 1024 ))MB extra space included."
debug 'INFO' "$IMG_FILE is ${AFTER_SIZE}MB with $(( ADDED_SPACE / 1024 / 1024 ))MB extra space included"
fi
- if [ $AUTOEXPAND == true ]; then
- echo "## Please wait for the system to reboot after restoring an image with autoexpansion."
- fi
else
echo '## Backup done.'
echo '##############################################################################'
From 41593c0d64114879cabb9b68b19a84597ca3d54a Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Mon, 20 Nov 2023 14:09:51 +0100
Subject: [PATCH 02/23] Update shrink-backup
Trying to figure out best usage of parted vs sfdisk
---
shrink-backup | 69 ++++++++++++++++++++++-----------------------------
1 file changed, 30 insertions(+), 39 deletions(-)
diff --git a/shrink-backup b/shrink-backup
index f917bce..5a1581e 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
-# 11/2023
+# 10/2023
# Marcus Johansson
# https://github.com/UnconnectedBedna/shrink-backup
##############################################################################
@@ -168,30 +168,20 @@ function debug() {
function get_dev_variables() {
# Check if separate boot and root partition exists and set variables accordingly
- #LOCAL_DEV_MAJ=$(lsblk -lpo mountpoint,maj:min | grep '/ ' | awk '{print $2}' | cut -d : -f 1)
LOCAL_DEV_PTUUID=$(lsblk -lpo mountpoint,ptuuid | grep '/ ' | awk '{print $2}')
LOCAL_DEV_PATH=$(lsblk -lpo ptuuid,type,path | grep "$LOCAL_DEV_PTUUID" | grep 'disk' | awk '{print $3}')
- #LOCAL_ROOT_PARTN=$(lsblk -lpo mountpoint,partn | grep '/ ' | awk '{print $2}') # PARTN can only be used on arch :(
- #LOCAL_DEV_PATH=$(lsblk -lpo maj:min,type,path | grep "$LOCAL_DEV_MAJ" | grep 'disk' | awk '{print $3}')
debug 'DEBUG' "LOCAL_DEV_PTUUID=$LOCAL_DEV_PTUUID | LOCAL_DEV_PATH=$LOCAL_DEV_PATH"
if [ $(lsblk | grep -c 'boot') -ne 0 ]; then
debug 'INFO' 'Separate boot partition detected'
- #LOCAL_DEV_MIN=$(lsblk -lpo mountpoint,maj:min | grep '/boot' | awk '{print $2}' | cut -d : -f 2)
- #LOCAL_DEV_MIN=$(( LOCAL_DEV_MIN - 1 ))
- #LOCAL_DEV_PATH=$(lsblk -lpo maj:min,type,path | grep "${LOCAL_DEV_MAJ}:${LOCAL_DEV_MIN}" | grep 'disk' | awk '{print $3}')
LOCAL_DEV_BOOT_PATH=$(lsblk -lpo mountpoint,path | grep 'boot' | awk '{print $2}')
LOCAL_DEV_ROOT_PATH=$(lsblk -lpo mountpoint,path | grep '/ ' | awk '{print $2}')
debug 'DEBUG' "LOCAL_DEV_ROOT_PATH=${LOCAL_DEV_ROOT_PATH} | LOCAL_DEV_BOOT_PATH=$LOCAL_DEV_BOOT_PATH"
else
debug 'INFO' 'No boot partition detected'
- #LOCAL_DEV_MIN=$(lsblk -lpo mountpoint,maj:min | grep '/ ' | awk '{print $2}' | cut -d : -f 2)
- #LOCAL_DEV_MIN=$(( LOCAL_DEV_MIN - 1 ))
- #LOCAL_DEV_PATH=$(lsblk -lpo maj:min,type,path | grep "${LOCAL_DEV_MAJ}:${LOCAL_DEV_MIN}" | grep 'disk' | awk '{print $3}')
LOCAL_DEV_ROOT_PATH=$(lsblk -lpo mountpoint,path | grep '/ ' | awk '{print $2}')
debug 'DEBUG' "LOCAL_DEV_ROOT_PATH=$LOCAL_DEV_ROOT_PATH"
fi
LOCAL_ROOT_PARTN=$(parted -sm "$LOCAL_DEV_PATH" print | tail -1 | cut -d : -f 1)
- #debug 'DEBUG' "LOCAL_DEV_PATH=${LOCAL_DEV_PATH} | LOCAL_DEV_MAJ=$LOCAL_DEV_MAJ | LOCAL_ROOT_PARTN=$LOCAL_ROOT_PARTN"
debug 'DEBUG' "LOCAL_ROOT_PARTN=$LOCAL_ROOT_PARTN"
# Collecting data and making calculations
@@ -209,10 +199,10 @@ function get_dev_variables() {
LOCAL_RESIZE2FS_MIN=$(( LOCAL_RESIZE2FS_MIN * BLOCKSIZE )) # bytes
debug 'DEBUG' "LOCAL_RESIZE2FS_MIN=${LOCAL_RESIZE2FS_MIN} Bytes"
# Method 1, using the value of "size - available"
- LOCAL_DF_OUTPUT=( $(df / --output=size,avail | tail -1) ) # 1k blocks, 0 is the first position in an array
+ LOCAL_DF_OUTPUT=( $(df / -k --sync --output=size,avail | tail -1) ) # 1k blocks, 0 is the first position in an array
LOCAL_USED_SPACE=$(( (${LOCAL_DF_OUTPUT[0]} - ${LOCAL_DF_OUTPUT[1]}) * 1024 )) # bytes, df is in 1k blocks, 0 is the first position
# Method 2, using "used space" straight up
- #LOCAL_DF_OUTPUT=( $(df / --output=used | tail -1) ) # 1k blocks
+ #LOCAL_DF_OUTPUT=( $(df / -k --sync --output=used | tail -1) ) # 1k blocks
#LOCAL_USED_SPACE=$(( LOCAL_DF_OUTPUT * 1024 )) # bytes, df is in 1k blocks
ADDED_SPACE=$(( ADDED_SPACE * 1024 * 1024 )) # bytes
WIGGLEROOM=134217728 # 128MB = 134217728B, 192MB = 201326592B
@@ -457,20 +447,20 @@ function do_resize() {
echo '## Removing partition...'
sleep 1
- debug 'INFO' 'Using sfdisk to remove partition'
- debug 'DEBUG' "Running: sfdisk --delete $LOOP $IMG_ROOT_PARTN"
- #sfdisk --delete -f "$LOOP" "$IMG_ROOT_PARTN" # seems to fail if img size is very big
- #debug 'DEBUG' "Running: parted -s $LOOP rm $IMG_ROOT_PARTN"
- #parted -s "$LOOP" rm "$IMG_ROOT_PARTN" # does not work, still asking for user confirmation even though --script is used
- #debug 'INFO' 'Using parted to remove root partition'
+ #debug 'INFO' 'Using sfdisk to remove root partition'
+ debug 'INFO' 'Using parted to remove root partition'
+ #debug 'DEBUG' "Running: sfdisk --delete -f $LOOP $IMG_ROOT_PARTN"
+ debug 'DEBUG' "Running: parted -s -f $LOOP rm $IMG_ROOT_PARTN"
#debug 'DEBUG' "Running: printf 'Ignore\\\n'$IMG_ROOT_PARTN | parted $LOOP rm $IMG_ROOT_PARTN ---pretend-input-tty"
- if ! output=$(sfdisk --delete -f "$LOOP" "$IMG_ROOT_PARTN" 2>&1); then
- #if ! output=$(printf 'Ignore\n'$IMG_ROOT_PARTN | parted $LOOP rm $IMG_ROOT_PARTN ---pretend-input-tty 2>&1); then
- echo -e "$output\n## SFDISK FAILED!!!"
- #echo -e "$output\n## PARTED FAILED!!!"
+
+ #if ! output=$(sfdisk --delete -f "$LOOP" "$IMG_ROOT_PARTN" 2>&1); then # might fail if img size is very big
+ if ! output=$(parted -s -f "$LOOP" rm "$IMG_ROOT_PARTN" 2>&1); then # for some reason this line works here but not when creating img
+ #if ! output=$(printf 'Ignore\n'$IMG_ROOT_PARTN | parted $LOOP rm $IMG_ROOT_PARTN ---pretend-input-tty 2>&1); then # raspberry pi os does not like this method
+ #echo -e "$output\n## SFDISK FAILED!!!"
+ echo -e "$output\n## PARTED FAILED!!!"
debug 'BREAK'
- debug 'ERROR' "SFDISK FAILED:\n$output\n------------------------------------------------------------------------------"
- #debug 'ERROR' "PARTED FAILED:\n$output\n------------------------------------------------------------------------------"
+ #debug 'ERROR' "SFDISK FAILED:\n$output\n------------------------------------------------------------------------------"
+ debug 'ERROR' "PARTED FAILED:\n$output\n------------------------------------------------------------------------------"
exit 1
fi
@@ -521,10 +511,10 @@ function do_resize() {
echo '## Shrinking partition...'
sleep 1
debug 'INFO' 'Using parted to shrink partition'
- #debug 'DEBUG' "Running: parted -s -a none $LOOP unit B resizepart $IMG_ROOT_PARTN $TRUNCATE_TOTAL"
+ #debug 'DEBUG' "Running: parted -s -f -a none $LOOP unit B resizepart $IMG_ROOT_PARTN $TRUNCATE_TOTAL"
debug 'DEBUG' "Running: printf 'Yes\\\n' | parted -a none $LOOP unit B resizepart $IMG_ROOT_PARTN $TRUNCATE_TOTAL ---pretend-input-tty"
- #parted -s -a none "$LOOP" unit B resizepart "$IMG_ROOT_PARTN" "$TOTAL"
- #if ! output=$(parted -s -a none "$LOOP" unit B resizepart "$IMG_ROOT_PARTN" "$TRUNCATE_TOTAL" 2>&1); then # does not work, still asking for user confirmation even though --script is used
+
+ #if ! output=$(parted -s -f -a none "$LOOP" unit B resizepart "$IMG_ROOT_PARTN" "$TRUNCATE_TOTAL" 2>&1); then # does not work, still asking for user confirmation even though --script and -f (automatically answer "fix" to exceptions in script mode) is used
if ! output=$(printf 'Yes\n' | parted -a none "$LOOP" unit B resizepart "$IMG_ROOT_PARTN" "$TRUNCATE_TOTAL" ---pretend-input-tty 2>&1); then
echo -e "$output\n## PARTED FAILED!!!"
debug 'BREAK'
@@ -621,7 +611,7 @@ function make_img() {
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
- echo "# Estemated root usage: $(( $(df / --output=used | tail -1) / 1024 ))MB"
+ echo "# Estemated root usage: $(( $(df / -k --sync --output=used | tail -1) / 1024 ))MB"
if [ "$RESIZE2FS_RUN" == true ]; then
echo "# Resize2fs decide minimum (root partition): $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
echo "# Total img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
@@ -680,7 +670,7 @@ function make_img() {
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
- echo "# Estemated root usage: $(( $(df / --output=used | tail -1) / 1024 ))MB"
+ echo "# Estemated root usage: $(( $(df / -k --sync --output=used | tail -1) / 1024 ))MB"
if [ "$RESIZE2FS_RUN" == true ]; then
echo "# Resize2fs decide minimum (root partition): $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
echo "# Total img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
@@ -747,12 +737,14 @@ function make_img() {
echo '## Removing root partition...'
sleep 1
debug 'INFO' 'Using sfdisk to remove root partition'
- debug 'DEBUG' "Running: sfdisk --delete -f $LOOP $LOCAL_ROOT_PARTN"
- #parted -s "$LOOP" rm "$IMG_ROOT_PARTN" # does not work, still asking for user confirmation even though --script is used
#debug 'INFO' 'Using parted to remove root partition'
+ debug 'DEBUG' "Running: sfdisk --delete -f $LOOP $LOCAL_ROOT_PARTN"
+ #debug 'DEBUG' "Running: parted -s -f $LOOP rm $LOCAL_ROOT_PARTN"
#debug 'DEBUG' "Running: printf 'Ignore\\\n'$LOCAL_ROOT_PARTN | parted $LOOP rm $LOCAL_ROOT_PARTN ---pretend-input-tty"
- if ! output=$(sfdisk --delete -f "$LOOP" "$LOCAL_ROOT_PARTN" 2>&1); then # seems to fail if img size is very big
- #if ! output=$(printf 'Ignore\n'$LOCAL_ROOT_PARTN | parted $LOOP rm $LOCAL_ROOT_PARTN ---pretend-input-tty 2>&1); then # fails on raspberry pi os
+
+ if ! output=$(sfdisk --delete -f "$LOOP" "$LOCAL_ROOT_PARTN" 2>&1); then # might fail if img size is very big
+ #if ! output=$(parted -s -f "$LOOP" rm "$LOCAL_ROOT_PARTN" 2>&1); then # does not work, still asking for user confirmation even though --script and -f (automatically answer "fix" to exceptions in script mode) is used. faults with: "Error: Can't have a partition outside the disk!". for some reason this line works in the resizing function
+ #if ! output=$(printf 'Ignore\n'$LOCAL_ROOT_PARTN | parted $LOOP rm $LOCAL_ROOT_PARTN ---pretend-input-tty 2>&1); then # raspberry pi os does not like this method, keep for memory
echo -e "$output\n## SFDISK FAILED!!!"
#echo -e "$output\n## PARTED FAILED!!!"
debug 'BREAK'
@@ -884,7 +876,7 @@ function do_backup() {
echo "# New img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
echo "# Difference: $(( ADDED_SPACE / 1024 / 1024 ))MB"
else
- echo "# Estemated root usage: $(( $(df / --output=used | tail -1) / 1024 ))MB"
+ echo "# Estemated root usage: $(( $(df / -k --sync --output=used | tail -1) / 1024 ))MB"
echo "# Total img size: $(( IMG_SIZE / 1024 / 1024 ))MB"
fi
echo '##############################################################################'
@@ -924,7 +916,7 @@ function do_backup() {
echo "# Difference: $(( ADDED_SPACE / 1024 / 1024 ))MB"
else
- echo "# Used space on root: $(( $(df / --output=used | tail -1) / 1024 ))MB"
+ echo "# Used space on root: $(( $(df / -k --sync --output=used | tail -1) / 1024 ))MB"
echo "# Total img size: $(( IMG_SIZE / 1024 / 1024 ))MB"
fi
echo '# PRESS CTRL+C WITHIN 5s TO CANCEL!'
@@ -962,7 +954,6 @@ function do_backup() {
return 0
else
- echo '## Difference too small, no resizing needed...'
debug 'INFO' 'Img root partition is >=64MB smaller or <=512MB bigger compared size to resize2fs recommended minimum, not resizing'
sleep 1
fi
@@ -1081,7 +1072,7 @@ LOCAL_DEV_ROOT_PATH=\$(lsblk -lpo mountpoint,path | grep '/ ' | awk '{print \$2}
LOCAL_ROOT_START=\$(fdisk -lo start "\$LOCAL_DEV_PATH" | tail -1 | awk '{print \$1}') # blocks, 512B block size
LOCAL_ROOT_START=\$(( LOCAL_ROOT_START * 512 )) # bytes
-sfdisk --delete "\$LOCAL_DEV_PATH" "\$LOCAL_ROOT_PARTN"
+sfdisk --delete -f "\$LOCAL_DEV_PATH" "\$LOCAL_ROOT_PARTN"
parted -s -a none "\$LOCAL_DEV_PATH" unit B mkpart primary ext4 "\$LOCAL_ROOT_START" 100%
resize2fs -f "\$LOCAL_DEV_ROOT_PATH"
sync
@@ -1137,7 +1128,7 @@ LOCAL_DEV_ROOT_PATH=\$(lsblk -lpo mountpoint,path | grep '/ ' | awk '{print \$2}
LOCAL_ROOT_START=\$(fdisk -lo start "\$LOCAL_DEV_PATH" | tail -1 | awk '{print \$1}') # blocks, 512B block size
LOCAL_ROOT_START=\$(( LOCAL_ROOT_START * 512 )) # bytes
-sfdisk --delete "\$LOCAL_DEV_PATH" "\$LOCAL_ROOT_PARTN"
+sfdisk --delete -f "\$LOCAL_DEV_PATH" "\$LOCAL_ROOT_PARTN"
parted -s -a none "\$LOCAL_DEV_PATH" unit B mkpart primary ext4 "\$LOCAL_ROOT_START" 100%
resize2fs -f "\$LOCAL_DEV_ROOT_PATH"
sync
From cc286d008d289dd5659072973ea6746756627abc Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Mon, 20 Nov 2023 14:17:42 +0100
Subject: [PATCH 03/23] Update README.md
---
README.md | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 4d38999..05a4994 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ _I made this script because I wanted a universal method of backing up my SBC:s i
Autoexpansion tested on **Raspberry Pi** os (bookworm and older), **Armbian**, **Manjaro-arm** and **ArchLinuxARM** for rpi with **ext4** root partition.
**Latest release:** [shrink-backup.v0.9.4](https://github.com/UnconnectedBedna/shrink-backup/releases/download/v0.9.4/shrink-backup.v0.9.4.tar.gz)
-[**Testing branch**](https://github.com/UnconnectedBedna/shrink-backup/tree/testing) if you want to have the absolute latest version. Resizing of existing img file to minimum size and btrfs cloning is next on the roadmap and is being developed here.
+[Testing branch](https://github.com/UnconnectedBedna/shrink-backup/tree/testing) if you want to have the absolute latest version. Resizing of existing img file to minimum size and btrfs cloning is next on the roadmap and is being developed here.
**Very fast restore thanks to minimal size of img file.**
@@ -78,9 +78,10 @@ Use `-l` to write debug info into `shrink-backup.log` file located in the same d
**Applications used in the script:**
- fdisk
- sfdisk
-- dd
- parted
- e2fsck
+- resize2fs
+- dd
- truncate
- mkfs.ext4
- rsync
From 0832be3a514ba73153c034d83158e4606a11e517 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Wed, 22 Nov 2023 16:59:20 +0100
Subject: [PATCH 04/23] Update README.md
btrfs beta
---
README.md | 35 ++++++++++++++++++++++++++++++-----
1 file changed, 30 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 05a4994..cc3b2ed 100644
--- a/README.md
+++ b/README.md
@@ -2,14 +2,16 @@
_I made this script because I wanted a universal method of backing up my SBC:s into small img files as fast as possible (with rsync), indepentent of what os is in use._
-Autoexpansion tested on **Raspberry Pi** os (bookworm and older), **Armbian**, **Manjaro-arm** and **ArchLinuxARM** for rpi with **ext4** root partition.
+Autoexpansion tested on **Raspberry Pi** os (bookworm and older), **Armbian**, **Manjaro-arm** and **ArchLinuxARM** for rpi with **ext4** root partition.
+**btrfs** on root partition has been tested on **Manjaro-arm** and is still considered to be beta. Please see btrfs section at the bottom for more info.
**Latest release:** [shrink-backup.v0.9.4](https://github.com/UnconnectedBedna/shrink-backup/releases/download/v0.9.4/shrink-backup.v0.9.4.tar.gz)
-[Testing branch](https://github.com/UnconnectedBedna/shrink-backup/tree/testing) if you want to have the absolute latest version. Resizing of existing img file to minimum size and btrfs cloning is next on the roadmap and is being developed here.
+[Testing branch](https://github.com/UnconnectedBedna/shrink-backup/tree/testing) if you want to have the absolute latest version. Resizing of existing img file to minimum size and btrfs backups is next on the roadmap and is being developed here.
**Very fast restore thanks to minimal size of img file.**
**Can back up any device as long as root is `ext4`**
+`btrfs` is in beta.
Default device that will be backed up is determined by scanning what disk-device `root` resides on.
This means that _if_ `boot` is a partition, that partition must be on the **same device as `root`**.
Backing up/restoring, to/from: usb-stick `/dev/sdX` with Raspberry pi os has been tested and works. Ie, writing an sd-card img to a usb-stick and vice versa works.
@@ -32,7 +34,7 @@ Directory where .img file is created is automatically excluded in backup
########################################################################
Usage: sudo shrink-backup [-Uatyelh] imagefile.img [extra space (MB)]
-U Update the img file (rsync to existing img), [extra space] extends img size/root partition
- -a Let resize2fs decide minimum space (extra space is ignored)
+ -a Autoresize root partition (extra space is ignored)
When used in combination with -U:
Expand if img is +256MB smaller resize2fs recommended minimum, shrink if +512MB bigger
-t Use exclude.txt in same folder as script to set excluded directories
@@ -43,10 +45,10 @@ Usage: sudo shrink-backup [-Uatyelh] imagefile.img [extra space (MB)]
-h --help Show this help snippet
########################################################################
Examples:
-sudo shrink-backup -a /path/to/backup.img (create img, resize2fs calcualtes size)
+sudo shrink-backup -a /path/to/backup.img (create img, automatically set size)
sudo shrink-backup -e -y /path/to/backup.img 1024 (create img, ignore prompts, do not autoexpand, add 1024MB extra space)
sudo shrink-backup -Utl /path/to/backup.img (update img backup, use exclude.txt and write log to shrink-backup.log)
-sudo shrink-backup -Ua /path/to/backup.img (update img backup, resize2fs calculates and resizes img file if needed)
+sudo shrink-backup -Ua /path/to/backup.img (update img backup, automatically resize img file if needed)
sudo shrink-backup -U /path/to/backup.img 1024 (update img backup, expand img size/root partition with 1024MB)
```
@@ -89,6 +91,7 @@ Use `-l` to write debug info into `shrink-backup.log` file located in the same d
## Info
Theoretically the script should work on any device as long as root filesystem is `ext4`. But IMHO is best applied on ARM hardware.
+`btrfs` is usable but still experimental. Please see section about btrfs below for more information.
Since the script uses `lsblk` to figure out where the root resides it does not matter what device it is on.
Even if you forget to disable autoexpansion on a non supported system, the backup will not fail. :)
@@ -147,6 +150,28 @@ This is to protect from unessesary resizing operations most likely not needed.
If manually added space is used in combination with `-U`, the img file/root partition will be expanded by that amount. No checks are being performed to make sure the data you want to back up will actually fit.
Only expansion is possible with this method.
+## btrfs
+
+**This is still in experimental stage so [ideas & feedback](https://github.com/UnconnectedBedna/shrink-backup/discussions) is HIGHLY appreciated!**
+The subvolumes are mounted with default compression: `compress=zstd` (default means `zstd:3`)
+
+I am working against Manjaro-arm to create this functionality and the standard install creates root (`/@`) and home (`/@home`) subvolumes, so the script assumes this is the situation on ALL btrfs systems as of now.
+
+The backup img is **NOT a clone**. Snapshots are NOT used to create the backup.
+The `UUID` will change on the created img filesystem (btrfs is way more picky than ext4 about this), but in the case of Manjaro (and raspberry pi too for that matter), that does not matter since `PARTUUID` is used in mounting, and that stays the same, but users should be aware.
+Subvol id:s are NOT guaranteed to be the same.
+
+Instead of using btrfs send/recieve I opted for rsync, quck and dirty.
+Both in creation of a new img and when keeping it updated with `-U`.
+My resoning for this is that this script is primarily for creating bootable img files, NOT to create perfectly cloned backups. Speed is also a strong argument here.
+
+The goal in developement of this script is ALWAYS to: as fast as possible create an img file that you can write directly to a sd-card and boot. That goal does NOT mix well with also creating a perfectly cloned backup.
+This does mean the script careas MORE about the file integrity rather than the disk integrity. The compression f.ex might be different than on your root filesystem. Subvol id:s might change etc etc.
+But the main goal stays the same, the backup must contain ALL REQUESTED FILES, ie a bootable file backup. I do NOT want to be responsible for people loosing their data when using this script, hence this decision. :)
+
+All of this might change in the future though. Not the rsync part (I value speed very high), but the subvol id:s, compression and such is on my mind.
+F.ex if more subvols (or less) than root and home is used I want the script to be able to handle that.
+
**Thank you for using my software <3**
*"A backup is not really a backup until it has been restored"*
From 3fba614423fda3291248ebd9fe0cf05e240f7cdb Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Wed, 22 Nov 2023 17:00:19 +0100
Subject: [PATCH 05/23] Update shrink-backup
debug cleanup
code cleanup
btrfs beta
---
shrink-backup | 369 ++++++++++++++++++++++++++++++++++----------------
1 file changed, 254 insertions(+), 115 deletions(-)
diff --git a/shrink-backup b/shrink-backup
index 5a1581e..e33dd48 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
-# 10/2023
+# 11/2023
# Marcus Johansson
# https://github.com/UnconnectedBedna/shrink-backup
##############################################################################
@@ -45,6 +45,10 @@ function cleanup() {
umount "${TMP_DIR}${BOOT_PATH}"
debug 'DEBUG' "Unmounting boot partition in cleanup function: umount ${TMP_DIR}${BOOT_PATH}"
fi
+ if [ -n "$TMP_DIR" ] && grep -qs "${TMP_DIR}/home " /proc/mounts; then
+ umount "$TMP_DIR"/home
+ debug 'DEBUG' "Unmounting home partition in cleanup function: umount $TMP_DIR"
+ fi
if [ -n "$TMP_DIR" ] && grep -qs "$TMP_DIR " /proc/mounts; then
umount "$TMP_DIR"
debug 'DEBUG' "Unmounting root partition in cleanup function: umount $TMP_DIR"
@@ -103,7 +107,7 @@ Directory where .img file is created is automatically excluded in backup
########################################################################
Usage: sudo $(basename "$0") [-Uatyelh] imagefile.img [extra space (MB)]
-U Update the img file (rsync to existing img), [extra space] extends img size/root partition
- -a Let resize2fs decide minimum space (extra space is ignored)
+ -a Autoresize root partition (extra space is ignored)
When used in combination with -U:
Expand if img is +256MB smaller resize2fs recommended minimum, shrink if +512MB bigger
-t Use exclude.txt in same folder as script to set excluded directories
@@ -114,10 +118,10 @@ Usage: sudo $(basename "$0") [-Uatyelh] imagefile.img [extra space (MB)]
-h --help Show this help snippet
########################################################################
Examples:
-sudo $(basename "$0") -a /path/to/backup.img (create img, resize2fs calcualtes size)
+sudo $(basename "$0") -a /path/to/backup.img (create img, automatically set size)
sudo $(basename "$0") -e -y /path/to/backup.img 1024 (create img, ignore prompts, do not autoexpand, add 1024MB extra space)
sudo $(basename "$0") -Utl /path/to/backup.img (update img backup, use exclude.txt and write log to shrink-backup.log)
-sudo $(basename "$0") -Ua /path/to/backup.img (update img backup, resize2fs calculates and resizes img file if needed)
+sudo $(basename "$0") -Ua /path/to/backup.img (update img backup, automatically resizes img file if needed)
sudo $(basename "$0") -U /path/to/backup.img 1024 (update img backup, expand img size/root partition with 1024MB)
EOM
echo "$help"
@@ -167,18 +171,25 @@ function debug() {
# Function to gather device information
function get_dev_variables() {
- # Check if separate boot and root partition exists and set variables accordingly
- LOCAL_DEV_PTUUID=$(lsblk -lpo mountpoint,ptuuid | grep '/ ' | awk '{print $2}')
+ if [ "$FSTYPE" == 'ext4' ]; then
+ LOCAL_DEV_PTUUID=$(lsblk -lpo mountpoint,ptuuid | grep '/ ' | awk '{print $2}')
+ else
+ LOCAL_DEV_PTUUID=$(lsblk -lpo fsroots,ptuuid | grep '/ ' | awk '{print $2}')
+ fi
LOCAL_DEV_PATH=$(lsblk -lpo ptuuid,type,path | grep "$LOCAL_DEV_PTUUID" | grep 'disk' | awk '{print $3}')
debug 'DEBUG' "LOCAL_DEV_PTUUID=$LOCAL_DEV_PTUUID | LOCAL_DEV_PATH=$LOCAL_DEV_PATH"
+
+ # Check if separate boot and root partition exists and set variables accordingly
if [ $(lsblk | grep -c 'boot') -ne 0 ]; then
debug 'INFO' 'Separate boot partition detected'
LOCAL_DEV_BOOT_PATH=$(lsblk -lpo mountpoint,path | grep 'boot' | awk '{print $2}')
- LOCAL_DEV_ROOT_PATH=$(lsblk -lpo mountpoint,path | grep '/ ' | awk '{print $2}')
- debug 'DEBUG' "LOCAL_DEV_ROOT_PATH=${LOCAL_DEV_ROOT_PATH} | LOCAL_DEV_BOOT_PATH=$LOCAL_DEV_BOOT_PATH"
+ #LOCAL_DEV_ROOT_PATH=$(lsblk -lpo mountpoint,path | grep '/ ' | awk '{print $2}')
+ LOCAL_DEV_ROOT_PATH=$(mount | grep '/ ' | awk '{print $1}')
+ debug 'DEBUG' "LOCAL_DEV_BOOT_PATH=$LOCAL_DEV_BOOT_PATH | LOCAL_DEV_ROOT_PATH=$LOCAL_DEV_ROOT_PATH"
else
debug 'INFO' 'No boot partition detected'
- LOCAL_DEV_ROOT_PATH=$(lsblk -lpo mountpoint,path | grep '/ ' | awk '{print $2}')
+ #LOCAL_DEV_ROOT_PATH=$(lsblk -lpo mountpoint,path | grep '/ ' | awk '{print $2}')
+ LOCAL_DEV_ROOT_PATH=$(mount | grep '/ ' | awk '{print $1}')
debug 'DEBUG' "LOCAL_DEV_ROOT_PATH=$LOCAL_DEV_ROOT_PATH"
fi
LOCAL_ROOT_PARTN=$(parted -sm "$LOCAL_DEV_PATH" print | tail -1 | cut -d : -f 1)
@@ -194,10 +205,18 @@ function get_dev_variables() {
LOCAL_ROOT_START=$(( LOCAL_ROOT_START * 512 )) # bytes
LOCAL_BOOTSECTOR=$(( LOCAL_BOOTSECTOR * 512 )) # bytes
debug 'DEBUG' "LOCAL_ROOT_START=$LOCAL_ROOT_START Bytes | LOCAL_BOOTSECTOR=$LOCAL_BOOTSECTOR Bytes"
- BLOCKSIZE=$(dumpe2fs -h "$LOCAL_DEV_ROOT_PATH" | grep "Block size" | awk '{print $3}') # bytes
- LOCAL_RESIZE2FS_MIN=$(resize2fs -P "$LOCAL_DEV_ROOT_PATH" | awk '{print $7}' | tail -1) # blocks
- LOCAL_RESIZE2FS_MIN=$(( LOCAL_RESIZE2FS_MIN * BLOCKSIZE )) # bytes
- debug 'DEBUG' "LOCAL_RESIZE2FS_MIN=${LOCAL_RESIZE2FS_MIN} Bytes"
+ if [ $FSTYPE == 'ext4' ]; then
+ BLOCKSIZE=$(dumpe2fs -h "$LOCAL_DEV_ROOT_PATH" | grep "Block size" | awk '{print $3}') # bytes
+ LOCAL_RESIZE2FS_MIN=$(resize2fs -P "$LOCAL_DEV_ROOT_PATH" | awk '{print $7}') # blocks
+ LOCAL_RESIZE2FS_MIN=$(( LOCAL_RESIZE2FS_MIN * BLOCKSIZE )) # bytes
+ debug 'DEBUG' "LOCAL_RESIZE2FS_MIN=${LOCAL_RESIZE2FS_MIN} Bytes"
+ else
+ debug 'INFO' 'btrfs detected, using btrfs fi du to calculate recommended size and adding 192MB'
+ LOCAL_RESIZE2FS_MIN=$(btrfs filesystem du -s --raw / 2>/dev/null) # bytes
+ LOCAL_RESIZE2FS_MIN=$(echo "$LOCAL_RESIZE2FS_MIN" | tail -1 | awk '{print $1}')
+ LOCAL_RESIZE2FS_MIN=$(( LOCAL_RESIZE2FS_MIN + 201326592 )) # 192MB = 201326592B
+ debug 'DEBUG' "LOCAL_RESIZE2FS_MIN=$LOCAL_RESIZE2FS_MIN bytes"
+ fi
# Method 1, using the value of "size - available"
LOCAL_DF_OUTPUT=( $(df / -k --sync --output=size,avail | tail -1) ) # 1k blocks, 0 is the first position in an array
LOCAL_USED_SPACE=$(( (${LOCAL_DF_OUTPUT[0]} - ${LOCAL_DF_OUTPUT[1]}) * 1024 )) # bytes, df is in 1k blocks, 0 is the first position
@@ -207,14 +226,13 @@ function get_dev_variables() {
ADDED_SPACE=$(( ADDED_SPACE * 1024 * 1024 )) # bytes
WIGGLEROOM=134217728 # 128MB = 134217728B, 192MB = 201326592B
- # Use resize2fs to calulate size if option is selected
+ # Use resize2fs to set size if option is selected
if [ "$RESIZE2FS_RUN" == true ]; then
debug 'INFO' 'Setting TOTAL (space needed for files on root) to size calculated by resize2fs'
TOTAL=$LOCAL_RESIZE2FS_MIN # bytes
else
debug 'INFO' 'Calculating TOTAL (space needed for files on root) by adding LOCAL_USED_SPACE and ADDED_SPACE'
- debug 'DEBUG' "LOCAL_USED_SPACE=${LOCAL_USED_SPACE} Bytes"
- debug 'DEBUG' "ADDED_SPACE=${ADDED_SPACE} Bytes"
+ debug 'DEBUG' "LOCAL_USED_SPACE=${LOCAL_USED_SPACE} Bytes | ADDED_SPACE=${ADDED_SPACE} Bytes"
TOTAL=$(( LOCAL_USED_SPACE + ADDED_SPACE )) # bytes
fi
debug 'DEBUG' "TOTAL=${TOTAL} Bytes"
@@ -222,8 +240,6 @@ function get_dev_variables() {
TRUNCATE_TOTAL=$(( LOCAL_BOOTSECTOR + TOTAL )) # bytes
debug 'INFO' 'Calculating .img file size by adding LOCAL_BOOTSECTOR to TOTAL (only used in img creation)'
debug 'DEBUG' "TRUNCATE_TOTAL=${TRUNCATE_TOTAL} Bytes"
- #TRUNCATE_TOTAL=$(( BLOCKSIZE + LOCAL_BOOTSECTOR + TOTAL )) # bytes, this was when I was using end instead of start with fdisk
- #TRUNCATE_TOTAL=$(( ( 1 + 33 ) * BLOCKSIZE + TOTAL + LOCAL_BOOTSECTOR )) # bytes, something about GPT needing 33 extra blocks
# Add 128MB extra space if resize2fs reports bigger minimum than created
if [ "$UPDATE" == false ] && [ "$TOTAL" -lt "$LOCAL_RESIZE2FS_MIN" ]; then
@@ -241,7 +257,6 @@ function get_dev_variables() {
# Function to gather image information
function get_img_variables() {
- debug 'INFO' 'Using ls to find img size and convert to MB'
debug 'DEBUG' "Running: ls -l $IMG_FILE | awk '{print \$5}'"
IMG_SIZE=$(ls -l "$IMG_FILE" | awk '{print $5}')
debug 'DEBUG' "IMG_SIZE=$IMG_SIZE Bytes"
@@ -259,7 +274,6 @@ function get_shared_variables() {
if [ $(lsblk | grep -c 'boot') -ne 0 ]; then
debug 'INFO' 'Separate boot partition detected'
- debug 'INFO' 'Fetching boot mount path from fstab'
debug 'DEBUG' "Running: cat /etc/fstab | grep '/boot' | awk '{print \$2}'"
BOOT_PATH=$(cat /etc/fstab | grep '/boot' | awk '{print $2}')
IMG_DEV_BOOT_PATH='/dev/loop0p1'
@@ -292,7 +306,7 @@ function do_loop() {
-# Function to loop and mount img file
+# Function to mount img file
function do_mount() {
# Check for temp directory and create if needed
@@ -369,7 +383,7 @@ function do_e2fsck() {
if [ "$AUTOEXPAND" == true ]; then
echo '## Remounting for autoexpansion...'
debug 'INFO' 'Remounting for autoexpansion function'
- debug 'DEBUG' 'Running function: do_mount'
+ debug 'INFO' 'Running function: do_mount'
sleep 1
do_mount
fi
@@ -407,14 +421,13 @@ function do_resize() {
debug 'DEBUG' "TOTAL=$TOTAL Bytes | TOTALK=$TOTALK Kilobytes"
# Gather information
- debug 'INFO' 'Using lsblk to fetch root partition number'
+ debug 'INFO' 'Using parted to fetch root partition number'
debug 'DEBUG' "Running: parted -sm "$LOOP" print | tail -1 | cut -d : -f 1"
IMG_ROOT_PARTN=$(parted -sm "$LOOP" print | tail -1 | cut -d : -f 1)
debug 'DEBUG' "IMG_ROOT_PARTN=$IMG_ROOT_PARTN"
# Check img filesystem
- debug 'INFO' 'Scanning filesystem'
- debug 'DEBUG' 'Running function: do_e2fsck'
+ debug 'INFO' 'Running function: do_e2fsck'
do_e2fsck
if [ "$*" = 'expand' ]; then
@@ -431,7 +444,7 @@ function do_resize() {
echo "## Resizing image file..."
sleep 1
- debug 'INFO' 'Using truncate to resize img file'
+ debug 'INFO' "Using truncate to resize img file' to $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
debug 'DEBUG' "Running: truncate --size=$TRUNCATE_TOTAL $IMG_FILE"
if ! output=$(truncate --size="$TRUNCATE_TOTAL" "$IMG_FILE" 2>&1); then
echo -e "$output\n## TRUNCATE FAILED!!!"
@@ -442,7 +455,7 @@ function do_resize() {
# Loop img file
debug 'INFO' 'Re-looping img file to fetch new img size'
- debug 'DEBUG' 'Running function: do_loop'
+ debug 'INFO' 'Running function: do_loop'
do_loop
echo '## Removing partition...'
@@ -474,7 +487,6 @@ function do_resize() {
debug 'ERROR' "PARTED FAILED:\n$output\n------------------------------------------------------------------------------"
exit 1
fi
- debug 'DEBUG' "$output\n------------------------------------------------------------------------------"
echo '## Resizing filesystem...'
sleep 1
@@ -487,10 +499,10 @@ function do_resize() {
debug 'ERROR' "RESIZE2FS FAILED:\n$output\n------------------------------------------------------------------------------"
exit 1
fi
+ debug 'DEBUG' "$output\n------------------------------------------------------------------------------"
# Check img filesystem
- debug 'INFO' 'Scanning filesystem'
- debug 'DEBUG' 'Running function: do_e2fsck'
+ debug 'INFO' 'Running function: do_e2fsck'
do_e2fsck
elif [ "$*" = 'shrink' ]; then
@@ -511,6 +523,7 @@ function do_resize() {
echo '## Shrinking partition...'
sleep 1
debug 'INFO' 'Using parted to shrink partition'
+ debug 'BREAK'
#debug 'DEBUG' "Running: parted -s -f -a none $LOOP unit B resizepart $IMG_ROOT_PARTN $TRUNCATE_TOTAL"
debug 'DEBUG' "Running: printf 'Yes\\\n' | parted -a none $LOOP unit B resizepart $IMG_ROOT_PARTN $TRUNCATE_TOTAL ---pretend-input-tty"
@@ -594,10 +607,10 @@ function do_rsync() {
# Function to create a backup img file
function make_img() {
- debug 'DEBUG' 'Running function: get_dev_variables'
+ debug 'INFO' 'Running function: get_dev_variables'
get_dev_variables
- debug 'DEBUG' 'Running function: get_shared_variables'
+ debug 'INFO' 'Running function: get_shared_variables'
get_shared_variables
# Display information
@@ -605,26 +618,31 @@ function make_img() {
echo ''
echo '##############################################################################'
echo "# A backup will be created at $IMG_FILE"
+ if [ "$FSTYPE" == 'ext4' ]; then
+ echo '# ext4 filesystem detected on root'
+ else
+ echo '# btrfs filesystem detected on root'
+ fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
- echo "# Resize2fs decide size: $RESIZE2FS_RUN"
+ echo "# Autresize root partition: $RESIZE2FS_RUN"
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
echo "# Estemated root usage: $(( $(df / -k --sync --output=used | tail -1) / 1024 ))MB"
if [ "$RESIZE2FS_RUN" == true ]; then
- echo "# Resize2fs decide minimum (root partition): $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
+ echo "# Auto calculated size (root partition): $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
echo "# Total img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
else
echo "# Manually added space: $(( ADDED_SPACE / 1024 / 1024 ))MB"
echo "# Total img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB with $(( ADDED_SPACE / 1024 / 1024 ))MB extra space included."
if [ "$WIGGLE_USE" == true ]; then
echo '# ----------------------------------------------------------------------------'
- echo "# WARNING!!! Manually added space is smaller than resize2fs recommended minimum"
+ echo "# WARNING!!! Manually added space is smaller than calculated recommended minimum"
echo "# This does NOT mean the backup WILL fail, but CAN fail due to lack of space"
- echo "# Concider using the -a option or adding more space"
+ echo "# Concider using the -a option or manually adding more space"
echo "# Requested root size: $(( TOTAL / 1024 / 1024 ))MB"
- echo "# Resize2fs recommended minimum: $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
+ echo "# Calculated recommended minimum: $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
fi
fi
echo '##############################################################################'
@@ -633,13 +651,14 @@ function make_img() {
read -p "Do you want to continue? [y/n] " -n 1 -r
debug 'INFO' 'Do you want to continue? [y/n]'
if ! [[ "$REPLY" =~ ^[Yy]$ ]]; then
- debug 'USER_INPUT' 'Aborted by user, clean exit 2'
+ debug 'WARNING' 'Aborted by user, clean exit 2'
echo ''
echo 'Aborting...'
exit 2
fi
echo ''
- debug 'USER_INPUT' 'Y or y pressed to confirm'
+ debug 'INFO' 'Y or y pressed to confirm'
+ debug 'BREAK'
if test -f "$IMG_FILE"; then
debug 'WARNING' "$IMG_FILE ALREADY EXISTS!"
@@ -647,15 +666,15 @@ function make_img() {
echo "$IMG_FILE"
echo 'FILE ALREADY EXISTS!!!'
read -p "Do you want to overwrite? [y/n] " -n 1 -r
- debug 'INFO' 'Do you want to overwrite? [y/n]'
+ debug 'WARNING' 'Do you want to overwrite? [y/n]'
if ! [[ "$REPLY" =~ ^[Yy]$ ]]; then
- debug 'USER_INPUT' 'Aborted by user, clean exit 2'
+ debug 'WARNING' 'Aborted by user, clean exit 2'
echo ''
echo 'Aborting...'
exit 2
fi
echo ''
- debug 'USER_INPUT' 'Overwrite confirmed by user'
+ debug 'WARNING' 'Overwrite confirmed by user'
fi
else
@@ -664,37 +683,43 @@ function make_img() {
echo '##############################################################################'
echo '# DISABLE PROMPTS SELECTED (-y), NO WARNINGS ABOUT DELETION!!!'
echo "# A backup will be created at $IMG_FILE"
+ if [ "$FSTYPE" == 'ext4' ]; then
+ echo '# ext4 filesystem detected on root'
+ else
+ echo '# btrfs filesystem detected on root'
+ fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
- echo "# Resize2fs decide size: $RESIZE2FS_RUN"
+ echo "# Autresize root partition:: $RESIZE2FS_RUN"
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
echo "# Estemated root usage: $(( $(df / -k --sync --output=used | tail -1) / 1024 ))MB"
if [ "$RESIZE2FS_RUN" == true ]; then
- echo "# Resize2fs decide minimum (root partition): $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
+ echo "# Auto calculated size (root partition): $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
echo "# Total img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
else
echo "# Manually added space: $(( ADDED_SPACE / 1024 / 1024 ))MB"
echo "# Total img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB with $(( ADDED_SPACE / 1024 / 1024 ))MB extra space included."
if [ "$WIGGLE_USE" == true ]; then
echo '# ----------------------------------------------------------------------------'
- echo "# WARNING!!! Manually added space is smaller than resize2fs recommended minimum"
+ echo "# WARNING!!! Manually added space is smaller than calculated recommended minimum"
echo "# This does NOT mean the backup WILL fail, but CAN fail due to lack of space"
- echo "# Concider using the -a option or adding more space"
+ echo "# Concider using the -a option or manually adding more space"
echo "# Requested root size: $(( TOTAL / 1024 / 1024 ))MB"
- echo "# Resize2fs recommended minimum: $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
+ echo "# Calculated recommended minimum: $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
fi
fi
echo '# PRESS CTRL+C WITHIN 5s TO CANCEL!'
echo '##############################################################################'
sleep 6
debug 'INFO' '6 seconds passed, user did not stop operation'
+ debug 'BREAK'
fi
# Delete existing file if user validation above passed
if [ -f "$IMG_FILE" ]; then
- debug 'DEBUG' "Removing: $IMG_FILE"
+ debug 'WARNING' "Removing: $IMG_FILE"
echo '## Removing old img file...'
rm "$IMG_FILE"
sleep 1
@@ -729,7 +754,6 @@ function make_img() {
sleep 1
# Loop img file
- debug 'INFO' 'Looping img file'
debug 'DEBUG' 'Running function: do_loop'
do_loop
@@ -758,51 +782,150 @@ function make_img() {
echo '## Recreating root partition...'
sleep 1
debug 'INFO' 'Using parted to recreate root partition'
- debug 'DEBUG' "Running: parted -s -a none $LOOP unit B mkpart primary ext4 $LOCAL_ROOT_START 100%"
- if ! output=$(parted -s -a none "$LOOP" unit B mkpart primary ext4 "$LOCAL_ROOT_START" 100% 2>&1); then
- echo -e "$output\n## PARTED FAILED!!!"
- debug 'BREAK'
- debug 'ERROR' "PARTED FAILED:\n$output\n------------------------------------------------------------------------------"
- exit 1
+
+ if [ $FSTYPE == 'ext4' ]; then
+ debug 'DEBUG' "Running: parted -s -a none $LOOP unit B mkpart primary ext4 $LOCAL_ROOT_START 100%"
+ if ! output=$(parted -s -a none "$LOOP" unit B mkpart primary ext4 "$LOCAL_ROOT_START" 100% 2>&1); then
+ echo -e "$output\n## PARTED FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "PARTED FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+
+ else
+ debug 'DEBUG' "Running: parted -s -a none $LOOP unit B mkpart primary btrfs $LOCAL_ROOT_START 100%"
+ if ! output=$(parted -s -a none "$LOOP" unit B mkpart primary btrfs "$LOCAL_ROOT_START" 100% 2>&1); then
+ echo -e "$output\n## PARTED FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "PARTED FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
fi
sleep 1
# Format filesystem
echo '## Formatting filesystem...'
sleep 1
- debug 'INFO' 'Using mkfs.ext4 to format root filesystem'
- LABEL=( $(lsblk -o label "$LOCAL_DEV_ROOT_PATH" | tail -1) )
- UUID=( $(lsblk -o uuid "$LOCAL_DEV_ROOT_PATH" | tail -1) )
+ LABEL=$(lsblk -o label "$LOCAL_DEV_ROOT_PATH" | tail -1)
+ UUID=$(lsblk -o uuid "$LOCAL_DEV_ROOT_PATH" | tail -1)
+ debug 'DEBUG' "LABLEL=$LABEL | UUID=$UUID"
+
+ if [ $FSTYPE = 'ext4' ]; then
+ debug 'INFO' 'Using mkfs.ext4 to format root filesystem'
+ if ! output=$(mkfs.ext4 "$IMG_DEV_ROOT_PATH" -U "$UUID" -L "$LABEL" -v 2>&1 | tee /dev/tty ); then
+ echo -e "$output\n## MKFS.EXT4 FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "MKFS.EXT4 FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ debug 'BREAK'
+ debug 'DEBUG' "Running: mkfs.ext4 $IMG_DEV_ROOT_PATH -U $UUID -L $LABEL -v\n$output\n------------------------------------------------------------------------------"
+ sleep 1
+
+ debug 'INFO' 'Running function: do_e2fsck'
+ do_e2fsck
- if ! output=$(mkfs.ext4 "$IMG_DEV_ROOT_PATH" -U "$UUID" -L "$LABEL" -v 2>&1 | tee /dev/tty ); then
- echo -e "$output\n## MKFS.EXT4 FAILED!!!"
+ debug 'INFO' 'Running function: do_mount'
+ do_mount
+
+ else
+ debug 'INFO' 'Using mkfs.btrfs to format root filesystem'
+ partprobe "$LOOP"
+ if ! output=$(mkfs.btrfs -m single -L "$LABEL" -f -v "$IMG_DEV_ROOT_PATH" 2>&1 | tee /dev/tty ); then # btrfs does NOT like having the same uuid on 2 filesystems at the same time
+ echo -e "$output\n## MKFS.BTRFS FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "MKFS.BTRFS FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
debug 'BREAK'
- debug 'ERROR' "MKFS.EXT4 FAILED:\n$output\n------------------------------------------------------------------------------"
- exit 1
- fi
- debug 'BREAK'
- debug 'DEBUG' "Running: mkfs.ext4 $IMG_DEV_ROOT_PATH -U $UUID -L $LABEL -F -v\n$output\n------------------------------------------------------------------------------"
- sleep 1
+ debug 'DEBUG' "Running: mkfs.btrfs -m single -L $LABEL -f -v $IMG_DEV_ROOT_PATH\n$output\n------------------------------------------------------------------------------"
+ sleep 1
- # Check img filesystem
- debug 'INFO' 'Scanning filesystem'
- debug 'DEBUG' 'Running function: do_e2fsck'
- do_e2fsck
+ # Check for temp directory and create if needed
+ if ! [ -d "$TMP_DIR" ]; then
+ echo '## Creating temp directory...'
+ sleep 1
+ debug 'INFO' 'Creating temp directory'
+ debug 'DEBUG' "Running: mktemp -d -t backup-XXXXXXXXXX"
+ TMP_DIR=$(mktemp -d -t backup-XXXXXXXXXX)
+ debug 'DEBUG' "TMP_DIR=$TMP_DIR"
+ fi
- # Mount img file
- debug 'INFO' 'Mounting img file'
- debug 'DEBUG' 'Running function: do_mount'
- do_mount
+ echo '## Creating btrfs subvolumes...'
+ debug 'INFO' 'Creating btrfs subvolumes'
+ debug 'DEBUG' "Running: mount -o compress=zstd $IMG_DEV_ROOT_PATH $TMP_DIR"
+ if ! output=$(mount -o compress=zstd "$IMG_DEV_ROOT_PATH" "$TMP_DIR" 2>&1); then
+ echo -e "$output\n## ROOT MOUNT FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "ROOT MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ sleep 1
+
+ debug 'DEBUG' "Running: btrfs subvolume create ${TMP_DIR}/@"
+ if ! output=$(btrfs subvolume create "$TMP_DIR"/@ 2>&1); then
+ echo -e "$output\n## CREATE ROOT SUBVOLUME FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "CREATE ROOT SUBVOLUME FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ sleep 1
+
+ debug 'DEBUG' "Running: btrfs subvolume create ${TMP_DIR}/@home"
+ if ! output=$(btrfs subvolume create "$TMP_DIR"/@home 2>&1); then
+ echo -e "$output\n## CREATE HOME SUBVOLUME FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "CREATE HOME SUBVOLUME FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ sleep 1
+
+ echo '## Mounting img btrfs subvolumes...'
+ debug 'INFO' 'Unmounting btrfs partition and mounting subvolumes'
+ umount "$TMP_DIR"
+ sleep 1
+
+ debug 'DEBUG' "Running: mount -o compress=zstd,subvol=@ $IMG_DEV_ROOT_PATH $TMP_DIR"
+ if ! output=$(mount -o compress=zstd,subvol=@ "$IMG_DEV_ROOT_PATH" "$TMP_DIR" 2>&1); then
+ echo -e "$output\n## ROOT SUBVOLUME MOUNT FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "ROOT SUBVOLUME MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ sleep 1
+
+ debug 'DEBUG' "Running: mount -o compress=zstd,subvol=@home $IMG_DEV_ROOT_PATH $TMP_DIR"
+ mkdir -p ${TMP_DIR}/home
+ if ! output=$(mount -o compress=zstd,subvol=@home "$IMG_DEV_ROOT_PATH" "$TMP_DIR"/home 2>&1); then
+ echo -e "$output\n## HOME SUBVOLUME MOUNT FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "HOME SUBVOLUME MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ sleep 1
+
+ echo '## Mounting boot...'
+ debug 'DEBUG' "Running: mount $IMG_DEV_BOOT_PATH ${TMP_DIR}${BOOT_PATH}"
+ mkdir -p ${TMP_DIR}${BOOT_PATH}
+ if ! output=$(mount "$IMG_DEV_BOOT_PATH" "${TMP_DIR}${BOOT_PATH}" 2>&1); then
+ echo -e "$output\n## BOOT MOUNT FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "BOOT MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ sleep 1
+ fi
# Copy files
debug 'INFO' 'Backing up files'
- debug 'DEBUG' 'Running function: do_rsync'
+ debug 'INFO' 'Running function: do_rsync'
do_rsync
- # Final check of created img file
- debug 'INFO' 'Finalizing filesystem'
- debug 'DEBUG' "Running do_e2fsck 'final'"
- do_e2fsck 'final'
+ if [ $FSTYPE == 'ext4' ]; then
+ # Final check of created img file
+ debug 'INFO' "Running do_e2fsck 'final'"
+ do_e2fsck 'final'
+ fi
return 0
}
@@ -819,20 +942,19 @@ function do_backup() {
exit 1
fi
- debug 'DEBUG' 'Running function: get_img_variables'
+ debug 'INFO' 'Running function: get_img_variables'
get_img_variables
- debug 'DEBUG' 'Running function: get_shared_variables'
+ debug 'INFO' 'Running function: get_shared_variables'
get_shared_variables
if [ "$RESIZE2FS_RUN" == true ] || [ "$ADDED_SPACE" -ne 0 ]; then
- debug 'DEBUG' 'Running function: get_dev_variables'
+ debug 'INFO' 'Running function: get_dev_variables'
get_dev_variables
fi
# Loop img file
- debug 'INFO' 'Looping img file'
- debug 'DEBUG' 'Running function: do_loop'
+ debug 'INFO' 'Running function: do_loop'
do_loop
# Checking if resizing should be performed
@@ -872,6 +994,7 @@ function do_backup() {
echo "# Difference: $DIFFERENCE"
elif [ "$ADDED_SPACE" -ne 0 ]; then
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
+ echo "# Estemated root usage: $(( $(df / -k --sync --output=used | tail -1) / 1024 ))MB"
echo "# Old img size: $(( IMG_SIZE / 1024 / 1024 ))MB"
echo "# New img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
echo "# Difference: $(( ADDED_SPACE / 1024 / 1024 ))MB"
@@ -885,13 +1008,14 @@ function do_backup() {
read -p "Do you want to continue? [y/n] " -n 1 -r
debug 'INFO' 'Do you want to continue? [y/n]'
if ! [[ "$REPLY" =~ ^[Yy]$ ]]; then
- debug 'USER_INPUT' 'Aborted by user, cleanup exit 3'
+ debug 'WARNING' 'Aborted by user, cleanup exit 3'
echo ''
echo 'Aborting...'
exit 3
fi
echo ''
- debug 'USER_INPUT' 'Y or y pressed to confirm'
+ debug 'INFO' 'Y or y pressed to confirm'
+ debug 'BREAK'
else
@@ -911,18 +1035,19 @@ function do_backup() {
echo "# Difference: $DIFFERENCE"
elif [ "$ADDED_SPACE" -ne 0 ]; then
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
+ echo "# Estemated root usage: $(( $(df / -k --sync --output=used | tail -1) / 1024 ))MB"
echo "# Old img size: $(( IMG_SIZE / 1024 / 1024 ))MB"
echo "# New img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
echo "# Difference: $(( ADDED_SPACE / 1024 / 1024 ))MB"
else
-
- echo "# Used space on root: $(( $(df / -k --sync --output=used | tail -1) / 1024 ))MB"
+ echo "# Estemated root usage: $(( $(df / -k --sync --output=used | tail -1) / 1024 ))MB"
echo "# Total img size: $(( IMG_SIZE / 1024 / 1024 ))MB"
fi
echo '# PRESS CTRL+C WITHIN 5s TO CANCEL!'
echo '##############################################################################'
sleep 6
debug 'INFO' '6 seconds passed, user did not stop operation'
+ debug 'BREAK'
fi
# Checking if resizing should be performed
@@ -930,7 +1055,7 @@ function do_backup() {
if [ "$IMG_ROOT_SIZE" -lt "$LOCAL_RESIZE2FS_MIN" ] && (( LOCAL_RESIZE2FS_MIN - IMG_ROOT_SIZE >= 268435456 )); then # 256MB in Bytes
debug 'INFO' 'Img root partition size is smaller than resize2fs recommended minimum'
debug 'DEBUG' "Difference=$diff MB"
- debug 'DEBUG' "Running function: do_resize 'expand'"
+ debug 'INFO' "Running function: do_resize 'expand'"
do_resize 'expand'
elif [ "$IMG_ROOT_SIZE" -gt "$LOCAL_RESIZE2FS_MIN" ] && (( IMG_ROOT_SIZE - LOCAL_RESIZE2FS_MIN >= 536870912 )); then # 512MB in Bytes
@@ -938,46 +1063,44 @@ function do_backup() {
debug 'DEBUG' "diff=$diff MB"
# Mount img file
- debug 'INFO' 'Mounting img file'
- debug 'DEBUG' 'Running function: do_mount'
+ debug 'INFO' 'Running function: do_mount'
do_mount
# Copy files
debug 'INFO' 'Backing up files'
- debug 'DEBUG' 'Running function: do_rsync'
+ debug 'INFO' 'Running function: do_rsync'
do_rsync
# Shrink img file
debug 'INFO' 'Shrinking img filesystem'
- debug 'DEBUG' "Running function: do_resize 'shrink'"
+ debug 'INFO' "Running function: do_resize 'shrink'"
do_resize 'shrink'
return 0
else
- debug 'INFO' 'Img root partition is >=64MB smaller or <=512MB bigger compared size to resize2fs recommended minimum, not resizing'
+ debug 'INFO' 'Img root partition is <=256MB smaller or <=512MB bigger compared size to resize2fs recommended minimum, not resizing'
sleep 1
fi
fi
# Expand img file if ADDED_SPACE not 0
if [ "$ADDED_SPACE" -ne 0 ]; then
- debug 'DEBUG' "Running function: do_resize 'expand'"
+ debug 'INFO' "Running function: do_resize 'expand'"
do_resize 'expand'
fi
# Mount img file
- debug 'INFO' 'Mounting img file'
- debug 'DEBUG' 'Running function: do_mount'
+ debug 'INFO' 'Running function: do_mount'
do_mount
# Copy files
debug 'INFO' 'Backing up files'
- debug 'DEBUG' 'Running function: do_rsync'
+ debug 'INFO' 'Running function: do_rsync'
do_rsync
# Final check of img filesystem
debug 'INFO' 'Finalizing filesystem'
- debug 'DEBUG' "Running do_e2fsck 'final'"
+ debug 'INFO' "Running do_e2fsck 'final'"
do_e2fsck 'final'
return 0
@@ -1180,6 +1303,7 @@ function print_result() {
fi
echo '##############################################################################'
debug 'INFO' 'Img file created and backup done'
+ debug 'BREAK'
return 0
}
@@ -1197,6 +1321,30 @@ do
fi
done
+echo '## Scanning filesystem and calculating...'
+
+# Check if debugging is requested
+if [ "$DEBUG" == true ]; then
+ echo "Debugging requested, writing to log file $LOG_FILE"
+ debug 'INFO' "Debugging requested, writing to log file $LOG_FILE"
+fi
+
+# Check what filesystem root is using
+if lsblk -lo mountpoint,fstype | grep '/ ' | grep -q 'ext4'; then
+ FSTYPE='ext4'
+ debug 'INFO' 'ext4 root filesystem detected'
+ debug 'DEBUG' "FSTYPE=$FSTYPE"
+else
+ FSTYPE='btrfs'
+ debug 'INFO' 'btrfs root filesystem detected'
+ debug 'DEBUG' "FSTYPE=$FSTYPE"
+fi
+
+debug 'DEBUG' "Update existing img file, UPDATE=$UPDATE"
+debug 'DEBUG' "Requesting size from resize2fs, RESIZE2FS_RUN=$RESIZE2FS_RUN"
+debug 'DEBUG' "Prompt for user confirmation, PROMPTS=$PROMPTS"
+debug 'DEBUG' "Auto expansion, AUTOEXPAND=$AUTOEXPAND"
+
# Setting ADDED_SPACE to 0 if RESIZE2FS_RUN option is enabled
if [ "$RESIZE2FS_RUN" == true ]; then
ADDED_SPACE=0
@@ -1245,40 +1393,31 @@ if [[ "$IMG_FILE" != *.img ]]; then
exit 2
fi
-# Check if debugging is requested
-if [ "$DEBUG" == true ]; then
- echo '## Scanning filesystem and calculating...'
- debug 'INFO' "Debugging requested, writing to log file $(basename "$LOG_FILE")..."
- debug 'INFO' "Update existing img file, UPDATE=$UPDATE"
- debug 'INFO' "Requesting size from resize2fs, RESIZE2FS_RUN=$RESIZE2FS_RUN"
- debug 'INFO' "Prompt for user confirmation, PROMPTS=$PROMPTS"
- debug 'INFO' "Auto expansion, AUTOEXPAND=$AUTOEXPAND"
-fi
-
# Check if usage of exclude.txt is requested
if [ "$EXCLUDE_FILE" == true ]; then
- debug 'INFO' '-f selected by user, using exclude.txt'
- debug 'DEBUG' 'Checking if EXCLUDE_FILE exists'
+ debug 'INFO' "-f selected by user, using $(dirname $0)/exclude.txt"
if ! [ -f $(dirname "$0")/exclude.txt ]; then
echo 'ERROR! exclude.txt is not present in script directory!'
debug 'ERROR' 'exclude.txt does not exist in script directory, exit 2'
exit 2
fi
- debug 'INFO' "$(dirname $0)/exclude.txt exists"
+ debug 'DEBUG' "$(dirname $0)/exclude.txt exists"
fi
if [ "$UPDATE" != true ]; then
- debug 'DEBUG' 'Executing make_img function'
+ debug 'INFO' 'Executing make_img function'
+ debug 'BREAK'
make_img
else
- debug 'DEBUG' 'User selected -U, executing do_backup function'
+ debug 'INFO' '-U sekected by user, executing do_backup function'
+ debug 'BREAK'
do_backup
fi
# Check if autoexpansion is requested and run required function
if [ "$AUTOEXPAND" == true ]; then
echo '## Enabling fs-autoexpand...'
- debug 'DEBUG' 'Executing expand_fs function'
+ debug 'INFO' 'Executing expand_fs function'
sleep 1
if cat /etc/os-release | grep -i 'manjaro' >/dev/null; then
echo '## Manjaro os detected...'
From 23027226ea10905a6f0041dc6754e0c3b4e6243f Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Wed, 22 Nov 2023 17:49:20 +0100
Subject: [PATCH 06/23] Update README.md
typo
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index cc3b2ed..1677a90 100644
--- a/README.md
+++ b/README.md
@@ -166,7 +166,7 @@ Both in creation of a new img and when keeping it updated with `-U`.
My resoning for this is that this script is primarily for creating bootable img files, NOT to create perfectly cloned backups. Speed is also a strong argument here.
The goal in developement of this script is ALWAYS to: as fast as possible create an img file that you can write directly to a sd-card and boot. That goal does NOT mix well with also creating a perfectly cloned backup.
-This does mean the script careas MORE about the file integrity rather than the disk integrity. The compression f.ex might be different than on your root filesystem. Subvol id:s might change etc etc.
+This does mean the script cares MORE about the file integrity rather than the disk integrity. The compression f.ex might be different than on your root filesystem. Subvol id:s might change etc etc.
But the main goal stays the same, the backup must contain ALL REQUESTED FILES, ie a bootable file backup. I do NOT want to be responsible for people loosing their data when using this script, hence this decision. :)
All of this might change in the future though. Not the rsync part (I value speed very high), but the subvol id:s, compression and such is on my mind.
From e47b6f185393064df5399722f0e2df0c286c7983 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Fri, 24 Nov 2023 03:04:18 +0100
Subject: [PATCH 07/23] Update shrink-backup
Script can now look up subvolumes and creates them
---
shrink-backup | 130 +++++++++++++++++++++++++++++++++-----------------
1 file changed, 86 insertions(+), 44 deletions(-)
diff --git a/shrink-backup b/shrink-backup
index e33dd48..ecaaedf 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -216,6 +216,10 @@ function get_dev_variables() {
LOCAL_RESIZE2FS_MIN=$(echo "$LOCAL_RESIZE2FS_MIN" | tail -1 | awk '{print $1}')
LOCAL_RESIZE2FS_MIN=$(( LOCAL_RESIZE2FS_MIN + 201326592 )) # 192MB = 201326592B
debug 'DEBUG' "LOCAL_RESIZE2FS_MIN=$LOCAL_RESIZE2FS_MIN bytes"
+ debug 'INFO' 'Fetching btrfs subvolume info'
+ #SUBVOLUMES=( $(sudo btrfs subvolume list / | awk '{print $2,$9}') )
+ SUBVOLUMES=( $(sudo btrfs subvolume list / | awk '{print $9}') )
+ #subvolumes_count=$(( ${#SUBVOLUMES[@]} / 2 ))
fi
# Method 1, using the value of "size - available"
LOCAL_DF_OUTPUT=( $(df / -k --sync --output=size,avail | tail -1) ) # 1k blocks, 0 is the first position in an array
@@ -444,7 +448,7 @@ function do_resize() {
echo "## Resizing image file..."
sleep 1
- debug 'INFO' "Using truncate to resize img file' to $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
+ debug 'INFO' "Using truncate to resize img file to $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
debug 'DEBUG' "Running: truncate --size=$TRUNCATE_TOTAL $IMG_FILE"
if ! output=$(truncate --size="$TRUNCATE_TOTAL" "$IMG_FILE" 2>&1); then
echo -e "$output\n## TRUNCATE FAILED!!!"
@@ -538,7 +542,7 @@ function do_resize() {
echo '## Shrinking img file...'
sleep 1
- debug 'INFO' 'Using truncate to shrink img file'
+ debug 'INFO' "Using truncate to shrink img file to $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
debug 'DEBUG' "Running: truncate --size=$TRUNCATE_TOTAL $IMG_FILE"
if ! output=$(truncate --size="$TRUNCATE_TOTAL" "$IMG_FILE" 2>&1); then
echo -e "$output\n## TRUNCATE FAILED!!!"
@@ -690,7 +694,7 @@ function make_img() {
fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
- echo "# Autresize root partition:: $RESIZE2FS_RUN"
+ echo "# Autresize root partition: $RESIZE2FS_RUN"
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
@@ -743,7 +747,7 @@ function make_img() {
# Truncate file to correct size
echo "## Resizing img file..."
sleep 1
- debug 'INFO' "Using truncate to resize img file' to $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
+ debug 'INFO' "Using truncate to resize img file to $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
debug 'DEBUG' "Running: truncate --size=$TRUNCATE_TOTAL $IMG_FILE"
if ! output=$(truncate --size="$TRUNCATE_TOTAL" "$IMG_FILE" 2>&1); then
echo -e "$output\n## TRUNCATE FAILED!!!"
@@ -810,6 +814,7 @@ function make_img() {
UUID=$(lsblk -o uuid "$LOCAL_DEV_ROOT_PATH" | tail -1)
debug 'DEBUG' "LABLEL=$LABEL | UUID=$UUID"
+ # ext4
if [ $FSTYPE = 'ext4' ]; then
debug 'INFO' 'Using mkfs.ext4 to format root filesystem'
if ! output=$(mkfs.ext4 "$IMG_DEV_ROOT_PATH" -U "$UUID" -L "$LABEL" -v 2>&1 | tee /dev/tty ); then
@@ -828,6 +833,7 @@ function make_img() {
debug 'INFO' 'Running function: do_mount'
do_mount
+ # btrfs
else
debug 'INFO' 'Using mkfs.btrfs to format root filesystem'
partprobe "$LOOP"
@@ -854,7 +860,7 @@ function make_img() {
echo '## Creating btrfs subvolumes...'
debug 'INFO' 'Creating btrfs subvolumes'
debug 'DEBUG' "Running: mount -o compress=zstd $IMG_DEV_ROOT_PATH $TMP_DIR"
- if ! output=$(mount -o compress=zstd "$IMG_DEV_ROOT_PATH" "$TMP_DIR" 2>&1); then
+ if ! output=$(mount -o noatime,compress=zstd "$IMG_DEV_ROOT_PATH" "$TMP_DIR" 2>&1); then
echo -e "$output\n## ROOT MOUNT FAILED!!!"
debug 'BREAK'
debug 'ERROR' "ROOT MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
@@ -862,47 +868,73 @@ function make_img() {
fi
sleep 1
- debug 'DEBUG' "Running: btrfs subvolume create ${TMP_DIR}/@"
- if ! output=$(btrfs subvolume create "$TMP_DIR"/@ 2>&1); then
- echo -e "$output\n## CREATE ROOT SUBVOLUME FAILED!!!"
- debug 'BREAK'
- debug 'ERROR' "CREATE ROOT SUBVOLUME FAILED:\n$output\n------------------------------------------------------------------------------"
- exit 1
- fi
- sleep 1
-
- debug 'DEBUG' "Running: btrfs subvolume create ${TMP_DIR}/@home"
- if ! output=$(btrfs subvolume create "$TMP_DIR"/@home 2>&1); then
- echo -e "$output\n## CREATE HOME SUBVOLUME FAILED!!!"
- debug 'BREAK'
- debug 'ERROR' "CREATE HOME SUBVOLUME FAILED:\n$output\n------------------------------------------------------------------------------"
- exit 1
- fi
- sleep 1
+ # Create top subvolumes, ${#SUBVOLUMES[@]} gives count
+ for ((i = 0; i < ${#SUBVOLUMES[@]}; i++)); do
+ SUBVOL_PATH="${SUBVOLUMES[i]}"
+ if [[ "$SUBVOL_PATH" == '@'* ]]; then
+ echo "## Creating subvolume: $SUBVOL_PATH"
+ debug 'DEBUG' "Running: btrfs subvolume create ${TMP_DIR}/${SUBVOL_PATH}"
+ if ! output=$(btrfs subvolume create "$TMP_DIR"/"$SUBVOL_PATH" 2>&1); then
+ echo -e "$output\n## CREATE SUBVOLUME FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "CREATE SUBVOLUME FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ fi
+ sleep 1
+ done
- echo '## Mounting img btrfs subvolumes...'
- debug 'INFO' 'Unmounting btrfs partition and mounting subvolumes'
+ debug 'INFO' 'Unmounting btrfs filesystem & mounting root subvolume.'
+ debug 'DEBUG' "Running: umount $TMP_DIR"
umount "$TMP_DIR"
sleep 1
-
- debug 'DEBUG' "Running: mount -o compress=zstd,subvol=@ $IMG_DEV_ROOT_PATH $TMP_DIR"
- if ! output=$(mount -o compress=zstd,subvol=@ "$IMG_DEV_ROOT_PATH" "$TMP_DIR" 2>&1); then
- echo -e "$output\n## ROOT SUBVOLUME MOUNT FAILED!!!"
- debug 'BREAK'
- debug 'ERROR' "ROOT SUBVOLUME MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
- exit 1
- fi
+ partprobe "$LOOP"
+ fstab=( $(cat /etc/fstab | grep "${SUBVOLUMES[0]}") )
+ debug 'DEBUG' "Running: mount -o ${fstab[3]} $IMG_DEV_ROOT_PATH $TMP_DIR"
+ mount -o ${fstab[3]} $IMG_DEV_ROOT_PATH $TMP_DIR
sleep 1
- debug 'DEBUG' "Running: mount -o compress=zstd,subvol=@home $IMG_DEV_ROOT_PATH $TMP_DIR"
- mkdir -p ${TMP_DIR}/home
- if ! output=$(mount -o compress=zstd,subvol=@home "$IMG_DEV_ROOT_PATH" "$TMP_DIR"/home 2>&1); then
- echo -e "$output\n## HOME SUBVOLUME MOUNT FAILED!!!"
- debug 'BREAK'
- debug 'ERROR' "HOME SUBVOLUME MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
- exit 1
- fi
+ for ((i = 0; i < ${#SUBVOLUMES[@]}; i++)); do
+ SUBVOL_PATH="${SUBVOLUMES[i]}"
+ if [[ "$SUBVOL_PATH" != '@'* ]]; then
+ debug 'DEBUG' "Running: mkdir -p $TMP_DIR/$(dirname $SUBVOL_PATH)"
+ mkdir -p $TMP_DIR/$(dirname $SUBVOL_PATH)
+
+ echo "## Creating subvolume: $SUBVOL_PATH"
+ debug 'DEBUG' "Running: btrfs subvolume create ${TMP_DIR}/${SUBVOL_PATH}"
+ if ! output=$(btrfs subvolume create "$TMP_DIR"/"$SUBVOL_PATH" 2>&1); then
+ echo -e "$output\n## CREATE SUBVOLUME FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "CREATE SUBVOLUME FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ fi
+ sleep 1
+ done
+
+ echo '## Mounting img btrfs subvolumes...'
+ debug 'INFO' 'Mounting subvolumes'
sleep 1
+ partprobe "$LOOP"
+
+ # Starting with i=1 so root is skipped
+ for ((i = 1; i < ${#SUBVOLUMES[@]}; i++)); do
+ SUBVOL_PATH="${SUBVOLUMES[i]}"
+ if $(cat /etc/fstab | grep -q "$SUBVOL_PATH"); then
+ fstab=( $(cat /etc/fstab | grep "$SUBVOL_PATH") )
+ debug 'DEBUG' "Running: mkdir -p ${TMP_DIR}${fstab[1]}"
+ mkdir -p ${TMP_DIR}${fstab[1]}
+ echo "## Mounting subvolume: $SUBVOL_PATH"
+ debug 'DEBUG' "Running: mount -o ${fstab[3]} $IMG_DEV_ROOT_PATH ${TMP_DIR}${fstab[1]}"
+ if ! output=$(mount -o "${fstab[3]}" "$IMG_DEV_ROOT_PATH" ${TMP_DIR}${fstab[1]} 2>&1); then
+ echo -e "$output\n## SUBVOLUME MOUNT FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "SUBVOLUME MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ fi
+ sleep 1
+ done
echo '## Mounting boot...'
debug 'DEBUG' "Running: mount $IMG_DEV_BOOT_PATH ${TMP_DIR}${BOOT_PATH}"
@@ -981,14 +1013,19 @@ function do_backup() {
if [ "$PROMPTS" == true ]; then
echo '##############################################################################'
echo "# Updating $IMG_FILE"
+ if [ "$FSTYPE" == 'ext4' ]; then
+ echo '# ext4 filesystem detected on root'
+ else
+ echo '# btrfs filesystem detected on root'
+ fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
- echo "# Resize2fs decide size: $RESIZE2FS_RUN"
+ echo "# Autresize root partition: $RESIZE2FS_RUN"
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
if [ "$RESIZE2FS_RUN" == true ]; then
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
- echo "# Resize2fs decide minimum (root partition): $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
+ echo "# Auto calculated size (root partition): $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
echo "# Old img size: $(( IMG_SIZE / 1024 / 1024 ))MB"
echo "# New img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
echo "# Difference: $DIFFERENCE"
@@ -1022,14 +1059,19 @@ function do_backup() {
echo '##############################################################################'
echo '# DISABLE PROMPTS SELECTED'
echo "# Updating $IMG_FILE"
+ if [ "$FSTYPE" == 'ext4' ]; then
+ echo '# ext4 filesystem detected on root'
+ else
+ echo '# btrfs filesystem detected on root'
+ fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
- echo "# Resize2fs decide size: $RESIZE2FS_RUN"
+ echo "# Autresize root partition: $RESIZE2FS_RUN"
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
if [ "$RESIZE2FS_RUN" == true ]; then
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
- echo "# Resize2fs decide minimum (root partition): $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
+ echo "# Auto calculated size (root partition): $(( LOCAL_RESIZE2FS_MIN / 1024 / 1024 ))MB"
echo "# Old img size: $(( IMG_SIZE / 1024 / 1024 ))MB"
echo "# New img size: $(( TRUNCATE_TOTAL / 1024 / 1024 ))MB"
echo "# Difference: $DIFFERENCE"
From 730fa777003539debfd1c497be745e5a4f982237 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Sat, 9 Dec 2023 13:38:56 +0100
Subject: [PATCH 08/23] Update README.md
Cleaning up
---
README.md | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 1677a90..4675f23 100644
--- a/README.md
+++ b/README.md
@@ -98,7 +98,7 @@ Even if you forget to disable autoexpansion on a non supported system, the backu
### Order of operations - Image creation:
1. Uses `lsblk` to figure out the correct disk device to back up.
2. Reads the block sizes of the partitions.
-3. Uses `dd` to create the boot part of the system + a few megabytes to include the filesystem on root. (this _can_ be a partition)
+3. Uses `dd` to create the `boot` part of the system + a few megabytes to include the filesystem on `root`. (this _can_ be a partition)
4. Removes and recreates the `root` partition, the size depends on options used when starting the script.
5. Creates the `root` filesystem with the same `UUID` and `LABEL` as the system you are backing up from. (_MUST_ be `ext4`)
6. Uses `rsync` to sync both partitions. (if more than one)
@@ -135,19 +135,23 @@ By using `-a` in combination with `-U` the script will resize the img file if ne
### Order of operations - Image update:
1. Probes the img file for information about partitions.
2. Mounts `root` partition with an offset for the loop.
-3. Checks if multiple partitions exists. If true, reads `fstab` on img file and mounts boot partition accordingly with an offset.
+3. Checks if multiple partitions exists. If true, reads `fstab` on img file and mounts `boot` partition accordingly with an offset.
4. Uses `rsync` to sync both partitions. (if more than one)
To update an existing img file simply use the `-U` option and the path to the img file.
Example: `sudo shrink-backup -U /path/to/backup.img`
-**Resizing img file when updating**
+### Resizing img file when updating
If `-a` is used in combination with `-U`, the script will compare the root partition on the img file to the size `resize2fs` recommends as minimum.
The img file needs to be **+256MB** smaller than `resize2fs` recommended minimum to be expanded.
The img file needs to be **+512MB** bigger than `resize2fs` recommended minimum to be shrunk.
This is to protect from unessesary resizing operations most likely not needed.
-If manually added space is used in combination with `-U`, the img file/root partition will be expanded by that amount. No checks are being performed to make sure the data you want to back up will actually fit.
+**Disclaimer**
+Resizing **always** includes a small risk of corruption, please use with care (ie do not abuse). If you know your system will increase, maybe it's better to just add manual space in the creation? And then when you close in on the limit, use manual method to add more space instead of constantly using `-Ua`.
+I have ran a lot of testing of this (on "weak" arm harware like rpi4) and it rarely fails, but it _does_ happen. I also run the backups over lan so that could also be a contributing factor for the failures. Just keep that in mind. :)
+
+If manually added space is used in combination with `-U`, the `root` partition on the img file will be expanded by that amount. No checks are being performed to make sure the data you want to back up will actually fit.
Only expansion is possible with this method.
## btrfs
From e7864f91074d5cf6c600d81a7a6fd196560f921c Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Sat, 9 Dec 2023 13:45:02 +0100
Subject: [PATCH 09/23] Update README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 4675f23..c2adc9f 100644
--- a/README.md
+++ b/README.md
@@ -159,7 +159,7 @@ Only expansion is possible with this method.
**This is still in experimental stage so [ideas & feedback](https://github.com/UnconnectedBedna/shrink-backup/discussions) is HIGHLY appreciated!**
The subvolumes are mounted with default compression: `compress=zstd` (default means `zstd:3`)
-I am working against Manjaro-arm to create this functionality and the standard install creates root (`/@`) and home (`/@home`) subvolumes, so the script assumes this is the situation on ALL btrfs systems as of now.
+I am working against Manjaro-arm to create this functionality and the standard install creates root (`/@`) and home (`/@home`) subvolumes (and some nested ones that will also be included), so the script assumes this is the situation on ALL btrfs systems as of now.
The backup img is **NOT a clone**. Snapshots are NOT used to create the backup.
The `UUID` will change on the created img filesystem (btrfs is way more picky than ext4 about this), but in the case of Manjaro (and raspberry pi too for that matter), that does not matter since `PARTUUID` is used in mounting, and that stays the same, but users should be aware.
@@ -170,7 +170,7 @@ Both in creation of a new img and when keeping it updated with `-U`.
My resoning for this is that this script is primarily for creating bootable img files, NOT to create perfectly cloned backups. Speed is also a strong argument here.
The goal in developement of this script is ALWAYS to: as fast as possible create an img file that you can write directly to a sd-card and boot. That goal does NOT mix well with also creating a perfectly cloned backup.
-This does mean the script cares MORE about the file integrity rather than the disk integrity. The compression f.ex might be different than on your root filesystem. Subvol id:s might change etc etc.
+This does mean the script cares MORE about the **file integrity** rather than the **filesystem integrity**. The compression f.ex might be different than on your root filesystem. Subvol id:s might change etc etc.
But the main goal stays the same, the backup must contain ALL REQUESTED FILES, ie a bootable file backup. I do NOT want to be responsible for people loosing their data when using this script, hence this decision. :)
All of this might change in the future though. Not the rsync part (I value speed very high), but the subvol id:s, compression and such is on my mind.
From fdd903f52d94989a2e751ed971719059d32e0501 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Sat, 9 Dec 2023 14:56:18 +0100
Subject: [PATCH 10/23] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index c2adc9f..08631b8 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ Backing up/restoring, to/from: usb-stick `/dev/sdX` with Raspberry pi os has bee
See [wiki](https://github.com/UnconnectedBedna/shrink-backup/wiki) for a bit more information about usage.
[Ideas and feedback](https://github.com/UnconnectedBedna/shrink-backup/discussions) is always appreciated, whether it's positive or negative. Please just keep it civil. :)
-**Don't forget to make the script executable.**
+**Assure the script is executable.**
**To restore a backup, simply "burn" the img file to a device using your favorite method.**
When booting up a restored image with autoresize active, wait until the the reboot sequence has occured. The login prompt may very well become visible before the autoresize function has rebooted.
From f63621c698728546ad4ad469d558f9bfe8285385 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Sat, 9 Dec 2023 15:11:49 +0100
Subject: [PATCH 11/23] Update README.md
typo
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 08631b8..4770003 100644
--- a/README.md
+++ b/README.md
@@ -145,7 +145,7 @@ Example: `sudo shrink-backup -U /path/to/backup.img`
If `-a` is used in combination with `-U`, the script will compare the root partition on the img file to the size `resize2fs` recommends as minimum.
The img file needs to be **+256MB** smaller than `resize2fs` recommended minimum to be expanded.
The img file needs to be **+512MB** bigger than `resize2fs` recommended minimum to be shrunk.
-This is to protect from unessesary resizing operations most likely not needed.
+This is to protect from unnecessary resizing operations most likely not needed.
**Disclaimer**
Resizing **always** includes a small risk of corruption, please use with care (ie do not abuse). If you know your system will increase, maybe it's better to just add manual space in the creation? And then when you close in on the limit, use manual method to add more space instead of constantly using `-Ua`.
From c1ce756fd8b2bacd895c878735fc1386e9df6f50 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Sat, 9 Dec 2023 15:12:59 +0100
Subject: [PATCH 12/23] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 4770003..1b95a86 100644
--- a/README.md
+++ b/README.md
@@ -151,7 +151,7 @@ This is to protect from unnecessary resizing operations most likely not needed.
Resizing **always** includes a small risk of corruption, please use with care (ie do not abuse). If you know your system will increase, maybe it's better to just add manual space in the creation? And then when you close in on the limit, use manual method to add more space instead of constantly using `-Ua`.
I have ran a lot of testing of this (on "weak" arm harware like rpi4) and it rarely fails, but it _does_ happen. I also run the backups over lan so that could also be a contributing factor for the failures. Just keep that in mind. :)
-If manually added space is used in combination with `-U`, the `root` partition on the img file will be expanded by that amount. No checks are being performed to make sure the data you want to back up will actually fit.
+If manually added space is used in combination with `-U`, the `root` partition on the img file will be expanded by that amount. **No checks are being performed to make sure the data you want to back up will actually fit.**
Only expansion is possible with this method.
## btrfs
From c6e0986bea7d44992dc6194c42d281b0bea0eeaf Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Mon, 25 Dec 2023 14:56:13 +0100
Subject: [PATCH 13/23] Update README.md
warning added for `ext4` and encryption
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 1b95a86..fdeeafb 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,8 @@ _I made this script because I wanted a universal method of backing up my SBC:s i
Autoexpansion tested on **Raspberry Pi** os (bookworm and older), **Armbian**, **Manjaro-arm** and **ArchLinuxARM** for rpi with **ext4** root partition.
**btrfs** on root partition has been tested on **Manjaro-arm** and is still considered to be beta. Please see btrfs section at the bottom for more info.
+**If you use encryption and `ext4`, use script at own risk. `fsck` is used multiple times on the backed up img (no risk to your running filesystem, it never touches that)**
+
**Latest release:** [shrink-backup.v0.9.4](https://github.com/UnconnectedBedna/shrink-backup/releases/download/v0.9.4/shrink-backup.v0.9.4.tar.gz)
[Testing branch](https://github.com/UnconnectedBedna/shrink-backup/tree/testing) if you want to have the absolute latest version. Resizing of existing img file to minimum size and btrfs backups is next on the roadmap and is being developed here.
From 762e0b9a209185bf3d819f5f901f62d199194dc4 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Wed, 10 Jan 2024 14:42:22 +0100
Subject: [PATCH 14/23] Update shrink-backup
quick fix for issue #25
---
shrink-backup | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/shrink-backup b/shrink-backup
index ecaaedf..30a5b89 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
-# 11/2023
+# 01/2024
# Marcus Johansson
# https://github.com/UnconnectedBedna/shrink-backup
##############################################################################
@@ -273,7 +273,7 @@ function get_img_variables() {
# Function for shared variables
function get_shared_variables() {
- LOOP='/dev/loop0'
+ LOOP=$(losetup -l)
debug 'DEBUG' "LOOP=$LOOP"
if [ $(lsblk | grep -c 'boot') -ne 0 ]; then
From a34586600a7c18af4ce940a75b2d6839b23a4447 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Wed, 10 Jan 2024 15:06:41 +0100
Subject: [PATCH 15/23] Update shrink-backup
More fixes for issue #25
---
shrink-backup | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/shrink-backup b/shrink-backup
index 30a5b89..24bbdfc 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -53,14 +53,17 @@ function cleanup() {
umount "$TMP_DIR"
debug 'DEBUG' "Unmounting root partition in cleanup function: umount $TMP_DIR"
fi
- if losetup /dev/loop0 &>/dev/null; then
- losetup -d /dev/loop0
- debug 'DEBUG' 'Removing loop0 in cleanup function: losetup -d /dev/loop0'
- fi
- if losetup /dev/loop1 &>/dev/null; then
- losetup -d /dev/loop1
- debug 'DEBUG' 'Removing loop1 in cleanup function: losetup -d /dev/loop1'
+ #if losetup /dev/loop0 &>/dev/null; then
+ if losetup "$LOOP" &>/dev/null; then
+ #losetup -d /dev/loop0
+ losetup -d "$LOOP"
+ #debug 'DEBUG' 'Removing loop0 in cleanup function: losetup -d /dev/loop0'
+ debug 'DEBUG' "Removing loop in cleanup function: losetup -d $LOOP"
fi
+# if losetup /dev/loop1 &>/dev/null; then
+# losetup -d /dev/loop1
+# debug 'DEBUG' 'Removing loop1 in cleanup function: losetup -d /dev/loop1'
+# fi
if [ -d "$TMP_DIR" ]; then
rm -rf "$TMP_DIR"
debug 'DEBUG' "Removing temp directory in cleanup function: rm -rf $TMP_DIR"
@@ -280,12 +283,15 @@ function get_shared_variables() {
debug 'INFO' 'Separate boot partition detected'
debug 'DEBUG' "Running: cat /etc/fstab | grep '/boot' | awk '{print \$2}'"
BOOT_PATH=$(cat /etc/fstab | grep '/boot' | awk '{print $2}')
- IMG_DEV_BOOT_PATH='/dev/loop0p1'
- IMG_DEV_ROOT_PATH='/dev/loop0p2'
+ #IMG_DEV_BOOT_PATH='/dev/loop0p1'
+ IMG_DEV_BOOT_PATH="${LOOP}p1"
+ #IMG_DEV_ROOT_PATH='/dev/loop0p2'
+ IMG_DEV_ROOT_PATH="${LOOP}p2"
debug 'DEBUG' "BOOT_PATH=$BOOT_PATH | IMG_DEV_BOOT_PATH=$IMG_DEV_BOOT_PATH | IMG_DEV_ROOT_PATH=$IMG_DEV_ROOT_PATH"
else
debug 'INFO' 'No boot partition detected'
- IMG_DEV_ROOT_PATH='/dev/loop0p1'
+ #IMG_DEV_ROOT_PATH='/dev/loop0p1'
+ IMG_DEV_ROOT_PATH="${LOOP}p1"
debug 'DEBUG' "IMG_DEV_ROOT_PATH=$IMG_DEV_ROOT_PATH"
fi
return 0
From dd30c7216da4c2242ab7c982f4f5280856a7a204 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Wed, 10 Jan 2024 15:25:00 +0100
Subject: [PATCH 16/23] Update shrink-backup
Hopefully final change for issue #25
---
shrink-backup | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/shrink-backup b/shrink-backup
index 24bbdfc..7ee8158 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -276,7 +276,7 @@ function get_img_variables() {
# Function for shared variables
function get_shared_variables() {
- LOOP=$(losetup -l)
+ LOOP=$(losetup -f)
debug 'DEBUG' "LOOP=$LOOP"
if [ $(lsblk | grep -c 'boot') -ne 0 ]; then
From e94e4c6cd2966ee425918868a1d452cbb82224c8 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Wed, 10 Jan 2024 22:34:47 +0100
Subject: [PATCH 17/23] Update shrink-backup
btrfs subvolumes are now compared to exclude.txt if EXCLUDE_FILE==true
---
shrink-backup | 265 ++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 213 insertions(+), 52 deletions(-)
diff --git a/shrink-backup b/shrink-backup
index 7ee8158..0777f37 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -214,15 +214,8 @@ function get_dev_variables() {
LOCAL_RESIZE2FS_MIN=$(( LOCAL_RESIZE2FS_MIN * BLOCKSIZE )) # bytes
debug 'DEBUG' "LOCAL_RESIZE2FS_MIN=${LOCAL_RESIZE2FS_MIN} Bytes"
else
- debug 'INFO' 'btrfs detected, using btrfs fi du to calculate recommended size and adding 192MB'
- LOCAL_RESIZE2FS_MIN=$(btrfs filesystem du -s --raw / 2>/dev/null) # bytes
- LOCAL_RESIZE2FS_MIN=$(echo "$LOCAL_RESIZE2FS_MIN" | tail -1 | awk '{print $1}')
- LOCAL_RESIZE2FS_MIN=$(( LOCAL_RESIZE2FS_MIN + 201326592 )) # 192MB = 201326592B
- debug 'DEBUG' "LOCAL_RESIZE2FS_MIN=$LOCAL_RESIZE2FS_MIN bytes"
- debug 'INFO' 'Fetching btrfs subvolume info'
- #SUBVOLUMES=( $(sudo btrfs subvolume list / | awk '{print $2,$9}') )
- SUBVOLUMES=( $(sudo btrfs subvolume list / | awk '{print $9}') )
- #subvolumes_count=$(( ${#SUBVOLUMES[@]} / 2 ))
+ debug 'INFO' 'Running function: get_btrfs_variables'
+ get_btrfs_variables
fi
# Method 1, using the value of "size - available"
LOCAL_DF_OUTPUT=( $(df / -k --sync --output=size,avail | tail -1) ) # 1k blocks, 0 is the first position in an array
@@ -261,6 +254,37 @@ function get_dev_variables() {
+# Function to gather btrfs information
+function get_btrfs_variables() {
+
+ if [ $RESIZE2FS_RUN == true ]; then
+ debug 'INFO' 'Using btrfs fi du to calculate recommended size and adding 192MB'
+ LOCAL_RESIZE2FS_MIN=$(btrfs filesystem du -s --raw / 2>/dev/null) # bytes
+ LOCAL_RESIZE2FS_MIN=$(echo "$LOCAL_RESIZE2FS_MIN" | tail -1 | awk '{print $1}')
+ LOCAL_RESIZE2FS_MIN=$(( LOCAL_RESIZE2FS_MIN + 201326592 )) # 192MB = 201326592B
+ debug 'DEBUG' "LOCAL_RESIZE2FS_MIN=$LOCAL_RESIZE2FS_MIN bytes"
+ fi
+ debug 'DEBUG' "Running: btrfs subvolume list / | awk '{print \$9}'"
+ #LOCAL_SUBVOLUMES=( $(sudo btrfs subvolume list / | awk '{print $2,$9}') )
+ LOCAL_SUBVOLUMES=( $(btrfs subvolume list / | awk '{print $9}') )
+ #local_subvolumes_count=$(( ${#LOCAL_SUBVOLUMES[@]} / 2 ))
+ debug 'DEBUG' "LOCAL_SUBVOLUMES=$(echo ${LOCAL_SUBVOLUMES[@]})"
+ if [ "$EXCLUDE_FILE" == true ]; then
+ debug 'INFO' 'Filtering out volumes from exclude.txt'
+ for ((i = 0; i < ${#LOCAL_SUBVOLUMES[@]}; i++)); do
+ if $(echo "/${LOCAL_SUBVOLUMES[i]}" | grep -q -f "$(dirname $0)/exclude.txt"); then
+ debug 'DEBUG' "Filtering out subvolume: ${LOCAL_SUBVOLUMES[i]}"
+ unset LOCAL_SUBVOLUMES["$i"]
+ fi
+ done
+ debug 'DEBUG' "After filtering, LOCAL_SUBVOLUMES=$(echo ${LOCAL_SUBVOLUMES[@]})"
+ fi
+
+ return 0
+}
+
+
+
# Function to gather image information
function get_img_variables() {
@@ -268,6 +292,35 @@ function get_img_variables() {
IMG_SIZE=$(ls -l "$IMG_FILE" | awk '{print $5}')
debug 'DEBUG' "IMG_SIZE=$IMG_SIZE Bytes"
+ if [ "$FSTYPE" == 'btrfs' ]; then
+ # Check for temp directory and create if needed
+ if ! [ -d "$TMP_DIR" ]; then
+ echo '## Creating temp directory...'
+ sleep 1
+ debug 'INFO' 'Creating temp directory'
+ debug 'DEBUG' "Running: mktemp -d -t backup-XXXXXXXXXX"
+ TMP_DIR=$(mktemp -d -t backup-XXXXXXXXXX)
+ debug 'DEBUG' "TMP_DIR=$TMP_DIR"
+ fi
+ sleep 1
+ partprobe "$LOOP"
+ fstab=( $(cat /etc/fstab | grep '/ ') )
+ debug 'INFO' 'Mounting root to find subvolumes'
+ debug 'DEBUG' "Running: mount -o ${fstab[3]} $IMG_DEV_ROOT_PATH $TMP_DIR"
+ if ! output=$(mount -o "${fstab[3]}" "$IMG_DEV_ROOT_PATH" "$TMP_DIR" 2>&1); then
+ echo -e "$output\n## ROOT MOUNT FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "ROOT MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ sleep 1
+ debug 'DEBUG' "Running: btrfs subvolume list $TMP_DIR | awk '{print \$9}'"
+ IMG_SUBVOLUMES=( $(btrfs subvolume list "$TMP_DIR" | awk '{print $9}') )
+ debug 'DEBUG' "IMG_SUBVOLUMES=$(echo ${IMG_SUBVOLUMES[@]})"
+ debug 'DEBUG' "Running: umount $TMP_DIR"
+ umount "$TMP_DIR"
+ fi
+
return 0
}
@@ -276,6 +329,7 @@ function get_img_variables() {
# Function for shared variables
function get_shared_variables() {
+ #LOOP='/dev/loop0'
LOOP=$(losetup -f)
debug 'DEBUG' "LOOP=$LOOP"
@@ -328,16 +382,86 @@ function do_mount() {
TMP_DIR=$(mktemp -d -t backup-XXXXXXXXXX)
debug 'DEBUG' "TMP_DIR=$TMP_DIR"
fi
-
- echo '## Mounting img root partition...'
sleep 1
- debug 'INFO' 'Mounting root partition from loop'
- debug 'DEBUG' "Running: mount $IMG_DEV_ROOT_PATH $TMP_DIR"
- if ! output=$(mount "$IMG_DEV_ROOT_PATH" "$TMP_DIR" 2>&1); then
- echo -e "$output\n## ROOT MOUNT FAILED!!!"
- debug 'BREAK'
- debug 'ERROR' "ROOT MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
- exit 1
+ partprobe "$LOOP"
+
+ # btrfs
+ if [ "$FSTYPE" = 'btrfs' ]; then
+ fstab=( $(cat /etc/fstab | grep '/ ') )
+ echo "## Mounting root subvolume..."
+ debug 'DEBUG' "Running: mount -o ${fstab[3]} $IMG_DEV_ROOT_PATH $TMP_DIR"
+ if ! output=$(mount -o "${fstab[3]}" "$IMG_DEV_ROOT_PATH" "$TMP_DIR" 2>&1); then
+ echo -e "$output\n## ROOT SUBVOLUME MOUNT FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "ROOT SUBVOLUME MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+ sleep 1
+
+ for ((i = 0; i < ${#LOCAL_SUBVOLUMES[@]}; i++)); do
+ SUBVOL_PATH="${LOCAL_SUBVOLUMES[i]}"
+ if $(cat /etc/fstab | grep -q "$SUBVOL_PATH") && [[ "$SUBVOL_PATH" != '@' ]]; then
+ fstab=( $(cat /etc/fstab | grep "$SUBVOL_PATH") )
+ if ! [ -d "${TMP_DIR}${fstab[1]}" ]; then
+ debug 'DEBUG' "Running: mkdir -p ${TMP_DIR}${fstab[1]}"
+ mkdir -p "${TMP_DIR}${fstab[1]}"
+ fi
+ echo "## Mounting subvolume: $SUBVOL_PATH"
+ debug 'DEBUG' "Running: mount -o ${fstab[3]} $IMG_DEV_ROOT_PATH ${TMP_DIR}${fstab[1]}"
+ if ! output=$(mount -o "${fstab[3]}" "$IMG_DEV_ROOT_PATH" ${TMP_DIR}${fstab[1]} 2>&1); then
+ echo -e "$output\n## SUBVOLUME MOUNT FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "SUBVOLUME MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+
+
+
+
+
+
+
+ elif [[ "$SUBVOL_PATH" != '@'* ]]; then
+ if ! [ -d "${TMP_DIR}/${SUBVOL_PATH}" ]; then
+ #debug 'DEBUG' "Running: mkdir -p ${TMP_DIR}/$(dirname $SUBVOL_PATH)"
+ debug 'DEBUG' "Running: mkdir -p ${TMP_DIR}/${SUBVOL_PATH}"
+ #mkdir -p ${TMP_DIR}/$(dirname $SUBVOL_PATH)
+ mkdir -p "${TMP_DIR}/${SUBVOL_PATH}"
+ fi
+ fi
+ sleep 1
+ done
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ # ext4
+ else
+ echo '## Mounting img root partition...'
+ sleep 1
+ debug 'INFO' 'Mounting root partition from loop'
+ debug 'DEBUG' "Running: mount $IMG_DEV_ROOT_PATH $TMP_DIR"
+ if ! output=$(mount "$IMG_DEV_ROOT_PATH" "$TMP_DIR" 2>&1); then
+ echo -e "$output\n## ROOT MOUNT FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "ROOT MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
fi
# Checking if boot partition exists and if true mount boot
@@ -632,6 +756,8 @@ function make_img() {
echo '# ext4 filesystem detected on root'
else
echo '# btrfs filesystem detected on root'
+ echo "# ${#LOCAL_SUBVOLUMES[@]} subvolumes"
+ echo "# Subvolumes: ${LOCAL_SUBVOLUMES[@]}"
fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
@@ -697,6 +823,8 @@ function make_img() {
echo '# ext4 filesystem detected on root'
else
echo '# btrfs filesystem detected on root'
+ echo "# ${#LOCAL_SUBVOLUMES[@]} subvolumes"
+ echo "# Subvolumes: ${LOCAL_SUBVOLUMES[@]}"
fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
@@ -793,6 +921,7 @@ function make_img() {
sleep 1
debug 'INFO' 'Using parted to recreate root partition'
+ # ext4
if [ $FSTYPE == 'ext4' ]; then
debug 'DEBUG' "Running: parted -s -a none $LOOP unit B mkpart primary ext4 $LOCAL_ROOT_START 100%"
if ! output=$(parted -s -a none "$LOOP" unit B mkpart primary ext4 "$LOCAL_ROOT_START" 100% 2>&1); then
@@ -802,6 +931,7 @@ function make_img() {
exit 1
fi
+ # btrfs
else
debug 'DEBUG' "Running: parted -s -a none $LOOP unit B mkpart primary btrfs $LOCAL_ROOT_START 100%"
if ! output=$(parted -s -a none "$LOOP" unit B mkpart primary btrfs "$LOCAL_ROOT_START" 100% 2>&1); then
@@ -874,9 +1004,9 @@ function make_img() {
fi
sleep 1
- # Create top subvolumes, ${#SUBVOLUMES[@]} gives count
- for ((i = 0; i < ${#SUBVOLUMES[@]}; i++)); do
- SUBVOL_PATH="${SUBVOLUMES[i]}"
+ # Create top subvolumes, ${#LOCAL_SUBVOLUMES[@]} gives count
+ for ((i = 0; i < ${#LOCAL_SUBVOLUMES[@]}; i++)); do
+ SUBVOL_PATH="${LOCAL_SUBVOLUMES[i]}"
if [[ "$SUBVOL_PATH" == '@'* ]]; then
echo "## Creating subvolume: $SUBVOL_PATH"
debug 'DEBUG' "Running: btrfs subvolume create ${TMP_DIR}/${SUBVOL_PATH}"
@@ -890,52 +1020,75 @@ function make_img() {
sleep 1
done
- debug 'INFO' 'Unmounting btrfs filesystem & mounting root subvolume.'
+ echo '## Mounting root...'
+ debug 'INFO' 'Unmounting btrfs filesystem & mounting root subvolume'
debug 'DEBUG' "Running: umount $TMP_DIR"
umount "$TMP_DIR"
sleep 1
partprobe "$LOOP"
- fstab=( $(cat /etc/fstab | grep "${SUBVOLUMES[0]}") )
+ #fstab=( $(cat /etc/fstab | grep "${LOCAL_SUBVOLUMES[0]}") )
+ fstab=( $(cat /etc/fstab | grep '/ ') )
debug 'DEBUG' "Running: mount -o ${fstab[3]} $IMG_DEV_ROOT_PATH $TMP_DIR"
- mount -o ${fstab[3]} $IMG_DEV_ROOT_PATH $TMP_DIR
+ if ! output=$(mount -o "${fstab[3]}" "$IMG_DEV_ROOT_PATH" "$TMP_DIR" 2>&1); then
+ echo -e "$output\n## ROOT SUBVOLUME MOUNT FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "ROOT SUBVOLUME MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
sleep 1
- for ((i = 0; i < ${#SUBVOLUMES[@]}; i++)); do
- SUBVOL_PATH="${SUBVOLUMES[i]}"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ # Create nested volumes/snapshots
+ debug 'INFO' 'Creating nested volumes/snapshots'
+ for ((i = 0; i < ${#LOCAL_SUBVOLUMES[@]}; i++)); do
+ SUBVOL_PATH="${LOCAL_SUBVOLUMES[i]}"
if [[ "$SUBVOL_PATH" != '@'* ]]; then
debug 'DEBUG' "Running: mkdir -p $TMP_DIR/$(dirname $SUBVOL_PATH)"
mkdir -p $TMP_DIR/$(dirname $SUBVOL_PATH)
- echo "## Creating subvolume: $SUBVOL_PATH"
+ echo "## Creating volume: $SUBVOL_PATH"
debug 'DEBUG' "Running: btrfs subvolume create ${TMP_DIR}/${SUBVOL_PATH}"
if ! output=$(btrfs subvolume create "$TMP_DIR"/"$SUBVOL_PATH" 2>&1); then
- echo -e "$output\n## CREATE SUBVOLUME FAILED!!!"
+ echo -e "$output\n## CREATE VOLUME FAILED!!!"
debug 'BREAK'
- debug 'ERROR' "CREATE SUBVOLUME FAILED:\n$output\n------------------------------------------------------------------------------"
+ debug 'ERROR' "CREATE VOLUME FAILED:\n$output\n------------------------------------------------------------------------------"
exit 1
fi
fi
sleep 1
done
- echo '## Mounting img btrfs subvolumes...'
- debug 'INFO' 'Mounting subvolumes'
+ echo '## Mounting img btrfs volumes...'
+ debug 'INFO' 'Mounting volumes'
sleep 1
partprobe "$LOOP"
- # Starting with i=1 so root is skipped
- for ((i = 1; i < ${#SUBVOLUMES[@]}; i++)); do
- SUBVOL_PATH="${SUBVOLUMES[i]}"
- if $(cat /etc/fstab | grep -q "$SUBVOL_PATH"); then
+ for ((i = 0; i < ${#LOCAL_SUBVOLUMES[@]}; i++)); do
+ SUBVOL_PATH="${LOCAL_SUBVOLUMES[i]}"
+ if $(cat /etc/fstab | grep -q "$SUBVOL_PATH") && [[ "$SUBVOL_PATH" != '@' ]]; then
fstab=( $(cat /etc/fstab | grep "$SUBVOL_PATH") )
debug 'DEBUG' "Running: mkdir -p ${TMP_DIR}${fstab[1]}"
mkdir -p ${TMP_DIR}${fstab[1]}
echo "## Mounting subvolume: $SUBVOL_PATH"
debug 'DEBUG' "Running: mount -o ${fstab[3]} $IMG_DEV_ROOT_PATH ${TMP_DIR}${fstab[1]}"
if ! output=$(mount -o "${fstab[3]}" "$IMG_DEV_ROOT_PATH" ${TMP_DIR}${fstab[1]} 2>&1); then
- echo -e "$output\n## SUBVOLUME MOUNT FAILED!!!"
+ echo -e "$output\n## VOLUME MOUNT FAILED!!!"
debug 'BREAK'
- debug 'ERROR' "SUBVOLUME MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
+ debug 'ERROR' "VOLUME MOUNT FAILED:\n$output\n------------------------------------------------------------------------------"
exit 1
fi
fi
@@ -980,21 +1133,24 @@ function do_backup() {
exit 1
fi
- debug 'INFO' 'Running function: get_img_variables'
- get_img_variables
-
debug 'INFO' 'Running function: get_shared_variables'
get_shared_variables
+ debug 'INFO' 'Running function: do_loop'
+ do_loop
+
+ debug 'INFO' 'Running function: get_img_variables'
+ get_img_variables
+
if [ "$RESIZE2FS_RUN" == true ] || [ "$ADDED_SPACE" -ne 0 ]; then
debug 'INFO' 'Running function: get_dev_variables'
+ # get_btrfs_variables is run within get_dev_variables
get_dev_variables
+ elif [ "$FSTYPE" == 'btrfs' ] && [ "$RESIZE2FS_RUN" == false ] && [ "$ADDED_SPACE" -eq 0 ]; then
+ debug 'INFO' 'Running function: get_btrfs_variables'
+ get_btrfs_variables
fi
- # Loop img file
- debug 'INFO' 'Running function: do_loop'
- do_loop
-
# Checking if resizing should be performed
if [ "$RESIZE2FS_RUN" == true ]; then
debug 'DEBUG' "Running: fdisk --bytes -lo size $LOOP | tail -1"
@@ -1023,6 +1179,8 @@ function do_backup() {
echo '# ext4 filesystem detected on root'
else
echo '# btrfs filesystem detected on root'
+ echo "# ${#LOCAL_SUBVOLUMES[@]} subvolumes"
+ echo "# Subvolumes: ${LOCAL_SUBVOLUMES[@]}"
fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
@@ -1069,6 +1227,8 @@ function do_backup() {
echo '# ext4 filesystem detected on root'
else
echo '# btrfs filesystem detected on root'
+ echo "# ${#LOCAL_SUBVOLUMES[@]} subvolumes"
+ echo "# Subvolumes: ${LOCAL_SUBVOLUMES[@]}"
fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
@@ -1101,13 +1261,13 @@ function do_backup() {
# Checking if resizing should be performed
if [ "$RESIZE2FS_RUN" == true ]; then
if [ "$IMG_ROOT_SIZE" -lt "$LOCAL_RESIZE2FS_MIN" ] && (( LOCAL_RESIZE2FS_MIN - IMG_ROOT_SIZE >= 268435456 )); then # 256MB in Bytes
- debug 'INFO' 'Img root partition size is smaller than resize2fs recommended minimum'
+ debug 'INFO' 'Img root partition size is smaller than auto calculated size'
debug 'DEBUG' "Difference=$diff MB"
debug 'INFO' "Running function: do_resize 'expand'"
do_resize 'expand'
elif [ "$IMG_ROOT_SIZE" -gt "$LOCAL_RESIZE2FS_MIN" ] && (( IMG_ROOT_SIZE - LOCAL_RESIZE2FS_MIN >= 536870912 )); then # 512MB in Bytes
- debug 'INFO' 'Img root partition size is bigger than resize2fs recommended minimum'
+ debug 'INFO' 'Img root partition size is bigger than auto calculated size'
debug 'DEBUG' "diff=$diff MB"
# Mount img file
@@ -1126,7 +1286,7 @@ function do_backup() {
return 0
else
- debug 'INFO' 'Img root partition is <=256MB smaller or <=512MB bigger compared size to resize2fs recommended minimum, not resizing'
+ debug 'INFO' 'Img root partition is <=256MB smaller or <=512MB bigger compared to auto calculated size, not resizing'
sleep 1
fi
fi
@@ -1146,10 +1306,11 @@ function do_backup() {
debug 'INFO' 'Running function: do_rsync'
do_rsync
- # Final check of img filesystem
- debug 'INFO' 'Finalizing filesystem'
- debug 'INFO' "Running do_e2fsck 'final'"
- do_e2fsck 'final'
+ if [ $FSTYPE == 'ext4' ]; then
+ # Final check of created img file
+ debug 'INFO' "Running do_e2fsck 'final'"
+ do_e2fsck 'final'
+ fi
return 0
}
@@ -1373,7 +1534,7 @@ echo '## Scanning filesystem and calculating...'
# Check if debugging is requested
if [ "$DEBUG" == true ]; then
- echo "Debugging requested, writing to log file $LOG_FILE"
+ echo "## Debugging requested, writing to log file $LOG_FILE"
debug 'INFO' "Debugging requested, writing to log file $LOG_FILE"
fi
From aad3a781237d83b5efca95a4bff84bdcded63df9 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Fri, 19 Jan 2024 03:48:59 +0100
Subject: [PATCH 18/23] Update README.md
definition of size reference changed
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index fdeeafb..853edf9 100644
--- a/README.md
+++ b/README.md
@@ -145,8 +145,8 @@ Example: `sudo shrink-backup -U /path/to/backup.img`
### Resizing img file when updating
If `-a` is used in combination with `-U`, the script will compare the root partition on the img file to the size `resize2fs` recommends as minimum.
-The img file needs to be **+256MB** smaller than `resize2fs` recommended minimum to be expanded.
-The img file needs to be **+512MB** bigger than `resize2fs` recommended minimum to be shrunk.
+The img file needs to be **>=256MB** smaller than `resize2fs` recommended minimum to be expanded.
+The img file needs to be **>=512MB** bigger than `resize2fs` recommended minimum to be shrunk.
This is to protect from unnecessary resizing operations most likely not needed.
**Disclaimer**
From 19bf23db8a8e243366a044da06fce777b7f4daa6 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Sun, 21 Jan 2024 17:32:30 +0100
Subject: [PATCH 19/23] Update README.md
Changed the definition of size from MB to "traditional binary system"
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 853edf9..5359b62 100644
--- a/README.md
+++ b/README.md
@@ -105,7 +105,7 @@ Even if you forget to disable autoexpansion on a non supported system, the backu
5. Creates the `root` filesystem with the same `UUID` and `LABEL` as the system you are backing up from. (_MUST_ be `ext4`)
6. Uses `rsync` to sync both partitions. (if more than one)
-Added space is added on top of `df` reported "used space", not the size of the partition. Added space is in MB, so if you want to add 1GB, add 1024.
+Added space is added on top of `df` reported "used space", not the size of the partition. Added space is in traditional binary system, so if you want to add 1GB, add 1024.
The script can be instructed to set the img size by requesting recomended minimum size from `e2fsck` by using the `-a` option.
This is not the absolute smallest size you can achieve but is the "safest" way to create a "smallest possible" img file.
From af3c565908941251f70f8e7b977d61acd35ef2e3 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Fri, 26 Jan 2024 18:20:50 +0100
Subject: [PATCH 20/23] Update shrink-backup
Adding experimental support for GPT partition table and btrfs.
Further testing is needed before pushing to main branch.
---
shrink-backup | 215 ++++++++++++++++++++++++++++++++------------------
1 file changed, 140 insertions(+), 75 deletions(-)
diff --git a/shrink-backup b/shrink-backup
index 0777f37..ec5872b 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -47,7 +47,7 @@ function cleanup() {
fi
if [ -n "$TMP_DIR" ] && grep -qs "${TMP_DIR}/home " /proc/mounts; then
umount "$TMP_DIR"/home
- debug 'DEBUG' "Unmounting home partition in cleanup function: umount $TMP_DIR"
+ debug 'DEBUG' "Unmounting home partition in cleanup function: umount ${TMP_DIR}/home"
fi
if [ -n "$TMP_DIR" ] && grep -qs "$TMP_DIR " /proc/mounts; then
umount "$TMP_DIR"
@@ -174,13 +174,13 @@ function debug() {
# Function to gather device information
function get_dev_variables() {
- if [ "$FSTYPE" == 'ext4' ]; then
- LOCAL_DEV_PTUUID=$(lsblk -lpo mountpoint,ptuuid | grep '/ ' | awk '{print $2}')
- else
- LOCAL_DEV_PTUUID=$(lsblk -lpo fsroots,ptuuid | grep '/ ' | awk '{print $2}')
- fi
- LOCAL_DEV_PATH=$(lsblk -lpo ptuuid,type,path | grep "$LOCAL_DEV_PTUUID" | grep 'disk' | awk '{print $3}')
- debug 'DEBUG' "LOCAL_DEV_PTUUID=$LOCAL_DEV_PTUUID | LOCAL_DEV_PATH=$LOCAL_DEV_PATH"
+# if [ "$FSTYPE" == 'ext4' ]; then
+# LOCAL_DEV_PTUUID=$(lsblk -lpo mountpoint,ptuuid | grep '/ ' | awk '{print $2}')
+# else
+# LOCAL_DEV_PTUUID=$(lsblk -lpo fsroots,ptuuid | grep '/ ' | awk '{print $2}')
+# fi
+# LOCAL_DEV_PATH=$(lsblk -lpo ptuuid,type,path | grep "$LOCAL_DEV_PTUUID" | grep 'disk' | awk '{print $3}')
+# debug 'DEBUG' "LOCAL_DEV_PTUUID=$LOCAL_DEV_PTUUID | LOCAL_DEV_PATH=$LOCAL_DEV_PATH"
# Check if separate boot and root partition exists and set variables accordingly
if [ $(lsblk | grep -c 'boot') -ne 0 ]; then
@@ -432,24 +432,24 @@ function do_mount() {
sleep 1
done
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# ext4
else
echo '## Mounting img root partition...'
@@ -597,12 +597,12 @@ function do_resize() {
#debug 'INFO' 'Using sfdisk to remove root partition'
debug 'INFO' 'Using parted to remove root partition'
#debug 'DEBUG' "Running: sfdisk --delete -f $LOOP $IMG_ROOT_PARTN"
- debug 'DEBUG' "Running: parted -s -f $LOOP rm $IMG_ROOT_PARTN"
+ debug 'DEBUG' "Running: parted -s $LOOP rm $IMG_ROOT_PARTN"
#debug 'DEBUG' "Running: printf 'Ignore\\\n'$IMG_ROOT_PARTN | parted $LOOP rm $IMG_ROOT_PARTN ---pretend-input-tty"
#if ! output=$(sfdisk --delete -f "$LOOP" "$IMG_ROOT_PARTN" 2>&1); then # might fail if img size is very big
- if ! output=$(parted -s -f "$LOOP" rm "$IMG_ROOT_PARTN" 2>&1); then # for some reason this line works here but not when creating img
- #if ! output=$(printf 'Ignore\n'$IMG_ROOT_PARTN | parted $LOOP rm $IMG_ROOT_PARTN ---pretend-input-tty 2>&1); then # raspberry pi os does not like this method
+ if ! output=$(parted -s "$LOOP" rm "$IMG_ROOT_PARTN" 2>&1); then # for some reason this line works here but not when creating img
+ #if ! output=$(printf 'Ignore\n'$IMG_ROOT_PARTN | parted $LOOP rm $IMG_ROOT_PARTN ---pretend-input-tty 2>&1); then # raspberry pi os does not like this method, keep for memory
#echo -e "$output\n## SFDISK FAILED!!!"
echo -e "$output\n## PARTED FAILED!!!"
debug 'BREAK'
@@ -658,10 +658,10 @@ function do_resize() {
sleep 1
debug 'INFO' 'Using parted to shrink partition'
debug 'BREAK'
- #debug 'DEBUG' "Running: parted -s -f -a none $LOOP unit B resizepart $IMG_ROOT_PARTN $TRUNCATE_TOTAL"
+ #debug 'DEBUG' "Running: parted -s -a none $LOOP unit B resizepart $IMG_ROOT_PARTN $TRUNCATE_TOTAL"
debug 'DEBUG' "Running: printf 'Yes\\\n' | parted -a none $LOOP unit B resizepart $IMG_ROOT_PARTN $TRUNCATE_TOTAL ---pretend-input-tty"
- #if ! output=$(parted -s -f -a none "$LOOP" unit B resizepart "$IMG_ROOT_PARTN" "$TRUNCATE_TOTAL" 2>&1); then # does not work, still asking for user confirmation even though --script and -f (automatically answer "fix" to exceptions in script mode) is used
+ #if ! output=$(parted -s -a none "$LOOP" unit B resizepart "$IMG_ROOT_PARTN" "$TRUNCATE_TOTAL" 2>&1); then # retry this after -f got removed, before = does not work, still asking for user confirmation even though --script and -f (automatically answer "fix" to exceptions in script mode) is used
if ! output=$(printf 'Yes\n' | parted -a none "$LOOP" unit B resizepart "$IMG_ROOT_PARTN" "$TRUNCATE_TOTAL" ---pretend-input-tty 2>&1); then
echo -e "$output\n## PARTED FAILED!!!"
debug 'BREAK'
@@ -756,12 +756,12 @@ function make_img() {
echo '# ext4 filesystem detected on root'
else
echo '# btrfs filesystem detected on root'
- echo "# ${#LOCAL_SUBVOLUMES[@]} subvolumes"
- echo "# Subvolumes: ${LOCAL_SUBVOLUMES[@]}"
+ echo "# ${#LOCAL_SUBVOLUMES[@]} btrfs volumes will be included"
+ echo "# btrfs volumes: ${LOCAL_SUBVOLUMES[@]}"
fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
- echo "# Autresize root partition: $RESIZE2FS_RUN"
+ echo "# Autresize img root partition: $RESIZE2FS_RUN"
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
@@ -789,7 +789,7 @@ function make_img() {
if ! [[ "$REPLY" =~ ^[Yy]$ ]]; then
debug 'WARNING' 'Aborted by user, clean exit 2'
echo ''
- echo 'Aborting...'
+ echo '## Aborting...'
exit 2
fi
echo ''
@@ -806,7 +806,7 @@ function make_img() {
if ! [[ "$REPLY" =~ ^[Yy]$ ]]; then
debug 'WARNING' 'Aborted by user, clean exit 2'
echo ''
- echo 'Aborting...'
+ echo '## Aborting...'
exit 2
fi
echo ''
@@ -823,12 +823,12 @@ function make_img() {
echo '# ext4 filesystem detected on root'
else
echo '# btrfs filesystem detected on root'
- echo "# ${#LOCAL_SUBVOLUMES[@]} subvolumes"
- echo "# Subvolumes: ${LOCAL_SUBVOLUMES[@]}"
+ echo "# ${#LOCAL_SUBVOLUMES[@]} btrfs volumes will be included"
+ echo "# btrfs volumes: ${LOCAL_SUBVOLUMES[@]}"
fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
- echo "# Autresize root partition: $RESIZE2FS_RUN"
+ echo "# Autresize img root partition: $RESIZE2FS_RUN"
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
echo "# Bootsector size: $(( LOCAL_BOOTSECTOR / 1024 / 1024 ))MB"
@@ -898,21 +898,74 @@ function make_img() {
# Remove partition
echo '## Removing root partition...'
sleep 1
- debug 'INFO' 'Using sfdisk to remove root partition'
- #debug 'INFO' 'Using parted to remove root partition'
- debug 'DEBUG' "Running: sfdisk --delete -f $LOOP $LOCAL_ROOT_PARTN"
- #debug 'DEBUG' "Running: parted -s -f $LOOP rm $LOCAL_ROOT_PARTN"
- #debug 'DEBUG' "Running: printf 'Ignore\\\n'$LOCAL_ROOT_PARTN | parted $LOOP rm $LOCAL_ROOT_PARTN ---pretend-input-tty"
-
- if ! output=$(sfdisk --delete -f "$LOOP" "$LOCAL_ROOT_PARTN" 2>&1); then # might fail if img size is very big
- #if ! output=$(parted -s -f "$LOOP" rm "$LOCAL_ROOT_PARTN" 2>&1); then # does not work, still asking for user confirmation even though --script and -f (automatically answer "fix" to exceptions in script mode) is used. faults with: "Error: Can't have a partition outside the disk!". for some reason this line works in the resizing function
- #if ! output=$(printf 'Ignore\n'$LOCAL_ROOT_PARTN | parted $LOOP rm $LOCAL_ROOT_PARTN ---pretend-input-tty 2>&1); then # raspberry pi os does not like this method, keep for memory
- echo -e "$output\n## SFDISK FAILED!!!"
- #echo -e "$output\n## PARTED FAILED!!!"
- debug 'BREAK'
- debug 'ERROR' "SFDISK FAILED:\n$output\n------------------------------------------------------------------------------"
- #debug 'ERROR' "PARTED FAILED:\n$output\n------------------------------------------------------------------------------"
- exit 1
+ if [ $PARTITION_TABLE == 'gpt' ]; then
+ echo '## GPT partition table detected, sgdisk is needed, checking if installed...'
+ sleep 1
+ if [[ ! -f $(which sgdisk 2>&1) ]]; then
+ echo '## sgdisk is NOT installed...'
+ read -p "Do you want to try to install? [y/n] " -n 1 -r
+ debug 'INFO' 'Do you want to try to install? [y/n]'
+ if ! [[ "$REPLY" =~ ^[Yy]$ ]]; then
+ debug 'WARNING' 'Aborted by user, clean exit 2'
+ echo ''
+ echo '## Aborting...'
+ exit 2
+ fi
+ echo ''
+ debug 'INFO' 'Y or y pressed to confirm'
+ if [[ -f $(which apt 2>&1) ]]; then
+ echo '## apt found, trying to install gdisk...'
+ debug 'DEBUG' 'Running: apt update -y && apt upgrade -y && apt install gdisk -y'
+ sleep 1
+ apt update -y && apt upgrade -y && apt install gdisk -y
+ sleep 1
+ elif [[ -f $(which pacman 2>&1) ]]; then
+ echo '## pacman found, trying to install gdisk...'
+ debug 'DEBUG' 'Running: pacman -Syu && pacman -S gptfdisk'
+ sleep 1
+ pacman -Syu && pacman -S gptfdisk
+ sleep 1
+ else
+ echo '## Did not manage to install sgdisk, please install gdisk and retry script...'
+ debug 'ERROR' 'Did not succeed in installing sgdisk, aborting exit 1'
+ echo '## Aborting...'
+ exit 1
+ fi
+
+ else
+
+ echo '## sgdisk is installed, resuming backup...'
+ sleep 1
+ fi
+
+ debug 'INFO' 'Using sgdisk to remove root partition'
+ debug 'DEBUG' "Running: sgdisk $LOOP -d $LOCAL_ROOT_PARTN"
+
+ if ! output=$(sgdisk "$LOOP" -d "$LOCAL_ROOT_PARTN" 2>&1); then
+ echo -e "$output\n## SGDISK FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "SGDISK FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
+
+ else
+
+ debug 'INFO' 'Using sfdisk to remove root partition'
+ #debug 'INFO' 'Using parted to remove root partition'
+ debug 'DEBUG' "Running: sfdisk --delete -f $LOOP $LOCAL_ROOT_PARTN"
+ #debug 'DEBUG' "Running: parted -s $LOOP rm $LOCAL_ROOT_PARTN"
+ #debug 'DEBUG' "Running: printf 'Ignore\\\n'$LOCAL_ROOT_PARTN | parted $LOOP rm $LOCAL_ROOT_PARTN ---pretend-input-tty"
+
+ if ! output=$(sfdisk --delete -f "$LOOP" "$LOCAL_ROOT_PARTN" 2>&1); then # might fail if img size is very big
+ #if ! output=$(parted -s "$LOOP" rm "$LOCAL_ROOT_PARTN" 2>&1); then # retry this after -f got removed, before = does not work, still asking for user confirmation even though --script and -f (automatically answer "fix" to exceptions in script mode) is used. faults with: "Error: Can't have a partition outside the disk!". for some reason this line works in the resizing function
+ #if ! output=$(printf 'Ignore\n'$LOCAL_ROOT_PARTN | parted $LOOP rm $LOCAL_ROOT_PARTN ---pretend-input-tty 2>&1); then # raspberry pi os does not like this method, keep for memory
+ echo -e "$output\n## SFDISK FAILED!!!"
+ #echo -e "$output\n## PARTED FAILED!!!"
+ debug 'BREAK'
+ debug 'ERROR' "SFDISK FAILED:\n$output\n------------------------------------------------------------------------------"
+ #debug 'ERROR' "PARTED FAILED:\n$output\n------------------------------------------------------------------------------"
+ exit 1
+ fi
fi
sleep 1
@@ -1037,21 +1090,21 @@ function make_img() {
fi
sleep 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# Create nested volumes/snapshots
debug 'INFO' 'Creating nested volumes/snapshots'
for ((i = 0; i < ${#LOCAL_SUBVOLUMES[@]}; i++)); do
@@ -1179,12 +1232,12 @@ function do_backup() {
echo '# ext4 filesystem detected on root'
else
echo '# btrfs filesystem detected on root'
- echo "# ${#LOCAL_SUBVOLUMES[@]} subvolumes"
- echo "# Subvolumes: ${LOCAL_SUBVOLUMES[@]}"
+ echo "# ${#LOCAL_SUBVOLUMES[@]} btrfs volumes will be included"
+ echo "# btrfs volumes: ${LOCAL_SUBVOLUMES[@]}"
fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
- echo "# Autresize root partition: $RESIZE2FS_RUN"
+ echo "# Autresize img root partition: $RESIZE2FS_RUN"
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
if [ "$RESIZE2FS_RUN" == true ]; then
@@ -1227,12 +1280,12 @@ function do_backup() {
echo '# ext4 filesystem detected on root'
else
echo '# btrfs filesystem detected on root'
- echo "# ${#LOCAL_SUBVOLUMES[@]} subvolumes"
- echo "# Subvolumes: ${LOCAL_SUBVOLUMES[@]}"
+ echo "# ${#LOCAL_SUBVOLUMES[@]} btrfs volumes will be included"
+ echo "# btrfs volumes: ${LOCAL_SUBVOLUMES[@]}"
fi
echo '# ----------------------------------------------------------------------------'
echo "# Write to logfile: $DEBUG"
- echo "# Autresize root partition: $RESIZE2FS_RUN"
+ echo "# Autresize img root partition: $RESIZE2FS_RUN"
echo "# Autoexpand filesystem at boot: $AUTOEXPAND"
echo "# Use exclude.txt: $EXCLUDE_FILE"
if [ "$RESIZE2FS_RUN" == true ]; then
@@ -1549,6 +1602,18 @@ else
debug 'DEBUG' "FSTYPE=$FSTYPE"
fi
+# Check what partition table is in use and set LOCAL_DEV_PATH
+if [ "$FSTYPE" == 'ext4' ]; then
+ LOCAL_DEV_PTUUID=$(lsblk -lpo mountpoint,ptuuid | grep '/ ' | awk '{print $2}')
+else
+ LOCAL_DEV_PTUUID=$(lsblk -lpo fsroots,ptuuid | grep '/ ' | awk '{print $2}')
+fi
+LOCAL_DEV_PATH=$(lsblk -lpo ptuuid,type,path | grep "$LOCAL_DEV_PTUUID" | grep 'disk' | awk '{print $3}')
+debug 'DEBUG' "LOCAL_DEV_PTUUID=$LOCAL_DEV_PTUUID | LOCAL_DEV_PATH=$LOCAL_DEV_PATH"
+
+PARTITION_TABLE=$(parted "$LOCAL_DEV_PATH" print | grep 'Partition Table' | awk '{print $3}')
+debug 'DEBUG' "PARTITION_TABLE=$PARTITION_TABLE"
+
debug 'DEBUG' "Update existing img file, UPDATE=$UPDATE"
debug 'DEBUG' "Requesting size from resize2fs, RESIZE2FS_RUN=$RESIZE2FS_RUN"
debug 'DEBUG' "Prompt for user confirmation, PROMPTS=$PROMPTS"
From 8649125c58bbabbd3078493ed635d7ad230a4b10 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Fri, 26 Jan 2024 18:26:34 +0100
Subject: [PATCH 21/23] Update shrink-backup
Forgot to clean up the empty spaces in script and adding reference to bug #14
---
shrink-backup | 41 +----------------------------------------
1 file changed, 1 insertion(+), 40 deletions(-)
diff --git a/shrink-backup b/shrink-backup
index ec5872b..bfb0d1c 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -415,12 +415,6 @@ function do_mount() {
exit 1
fi
-
-
-
-
-
-
elif [[ "$SUBVOL_PATH" != '@'* ]]; then
if ! [ -d "${TMP_DIR}/${SUBVOL_PATH}" ]; then
#debug 'DEBUG' "Running: mkdir -p ${TMP_DIR}/$(dirname $SUBVOL_PATH)"
@@ -432,24 +426,6 @@ function do_mount() {
sleep 1
done
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
# ext4
else
echo '## Mounting img root partition...'
@@ -929,7 +905,7 @@ function make_img() {
echo '## Did not manage to install sgdisk, please install gdisk and retry script...'
debug 'ERROR' 'Did not succeed in installing sgdisk, aborting exit 1'
echo '## Aborting...'
- exit 1
+ exit 1
fi
else
@@ -1090,21 +1066,6 @@ function make_img() {
fi
sleep 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
# Create nested volumes/snapshots
debug 'INFO' 'Creating nested volumes/snapshots'
for ((i = 0; i < ${#LOCAL_SUBVOLUMES[@]}; i++)); do
From 8a15077be6f3256d062a03d7535f36a556d0c110 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Sun, 28 Jan 2024 22:34:18 +0100
Subject: [PATCH 22/23] Update README.md
When editing the readme ON THE TESTING BRANCH it suddenly pushed to main branch for some reason, I missed that so now the branches are probably messed up. :(
THIS is the final change before release of v0.9.5
---
README.md | 69 ++++++++++++++++++++-----------------------------------
1 file changed, 25 insertions(+), 44 deletions(-)
diff --git a/README.md b/README.md
index 5359b62..60812c5 100644
--- a/README.md
+++ b/README.md
@@ -2,18 +2,15 @@
_I made this script because I wanted a universal method of backing up my SBC:s into small img files as fast as possible (with rsync), indepentent of what os is in use._
-Autoexpansion tested on **Raspberry Pi** os (bookworm and older), **Armbian**, **Manjaro-arm** and **ArchLinuxARM** for rpi with **ext4** root partition.
-**btrfs** on root partition has been tested on **Manjaro-arm** and is still considered to be beta. Please see btrfs section at the bottom for more info.
+Autoexpansion tested on **Raspberry Pi** os (bookworm and older), **Armbian**, **Manjaro-arm** and **ArchLinuxARM** for rpi with **ext4** root partition.
+(Now also experimental btrfs functionality, please read further down)
-**If you use encryption and `ext4`, use script at own risk. `fsck` is used multiple times on the backed up img (no risk to your running filesystem, it never touches that)**
-
-**Latest release:** [shrink-backup.v0.9.4](https://github.com/UnconnectedBedna/shrink-backup/releases/download/v0.9.4/shrink-backup.v0.9.4.tar.gz)
-[Testing branch](https://github.com/UnconnectedBedna/shrink-backup/tree/testing) if you want to have the absolute latest version. Resizing of existing img file to minimum size and btrfs backups is next on the roadmap and is being developed here.
+**Latest release:** [shrink-backup.v0.9.5](https://github.com/UnconnectedBedna/shrink-backup/releases/download/v0.9.5/shrink-backup.v0.9.5.tar.gz)
+[**Testing branch**](https://github.com/UnconnectedBedna/shrink-backup/tree/testing) if you want to have the absolute latest version, there might be bugs.
**Very fast restore thanks to minimal size of img file.**
**Can back up any device as long as root is `ext4`**
-`btrfs` is in beta.
Default device that will be backed up is determined by scanning what disk-device `root` resides on.
This means that _if_ `boot` is a partition, that partition must be on the **same device as `root`**.
Backing up/restoring, to/from: usb-stick `/dev/sdX` with Raspberry pi os has been tested and works. Ie, writing an sd-card img to a usb-stick and vice versa works.
@@ -23,7 +20,7 @@ Backing up/restoring, to/from: usb-stick `/dev/sdX` with Raspberry pi os has bee
See [wiki](https://github.com/UnconnectedBedna/shrink-backup/wiki) for a bit more information about usage.
[Ideas and feedback](https://github.com/UnconnectedBedna/shrink-backup/discussions) is always appreciated, whether it's positive or negative. Please just keep it civil. :)
-**Assure the script is executable.**
+**Don't forget to make the script executable.**
**To restore a backup, simply "burn" the img file to a device using your favorite method.**
When booting up a restored image with autoresize active, wait until the the reboot sequence has occured. The login prompt may very well become visible before the autoresize function has rebooted.
@@ -36,7 +33,7 @@ Directory where .img file is created is automatically excluded in backup
########################################################################
Usage: sudo shrink-backup [-Uatyelh] imagefile.img [extra space (MB)]
-U Update the img file (rsync to existing img), [extra space] extends img size/root partition
- -a Autoresize root partition (extra space is ignored)
+ -a Let resize2fs decide minimum space (extra space is ignored)
When used in combination with -U:
Expand if img is +256MB smaller resize2fs recommended minimum, shrink if +512MB bigger
-t Use exclude.txt in same folder as script to set excluded directories
@@ -47,10 +44,10 @@ Usage: sudo shrink-backup [-Uatyelh] imagefile.img [extra space (MB)]
-h --help Show this help snippet
########################################################################
Examples:
-sudo shrink-backup -a /path/to/backup.img (create img, automatically set size)
+sudo shrink-backup -a /path/to/backup.img (create img, resize2fs calcualtes size)
sudo shrink-backup -e -y /path/to/backup.img 1024 (create img, ignore prompts, do not autoexpand, add 1024MB extra space)
sudo shrink-backup -Utl /path/to/backup.img (update img backup, use exclude.txt and write log to shrink-backup.log)
-sudo shrink-backup -Ua /path/to/backup.img (update img backup, automatically resize img file if needed)
+sudo shrink-backup -Ua /path/to/backup.img (update img backup, resize2fs calculates and resizes img file if needed)
sudo shrink-backup -U /path/to/backup.img 1024 (update img backup, expand img size/root partition with 1024MB)
```
@@ -82,30 +79,29 @@ Use `-l` to write debug info into `shrink-backup.log` file located in the same d
**Applications used in the script:**
- fdisk
- sfdisk
+- dd
- parted
- e2fsck
-- resize2fs
-- dd
- truncate
- mkfs.ext4
- rsync
+- gidisk (sgdisk is needed if the partition table is GPT, the script will inform you)
## Info
Theoretically the script should work on any device as long as root filesystem is `ext4`. But IMHO is best applied on ARM hardware.
-`btrfs` is usable but still experimental. Please see section about btrfs below for more information.
Since the script uses `lsblk` to figure out where the root resides it does not matter what device it is on.
Even if you forget to disable autoexpansion on a non supported system, the backup will not fail. :)
### Order of operations - Image creation:
1. Uses `lsblk` to figure out the correct disk device to back up.
2. Reads the block sizes of the partitions.
-3. Uses `dd` to create the `boot` part of the system + a few megabytes to include the filesystem on `root`. (this _can_ be a partition)
+3. Uses `dd` to create the boot part of the system + a few megabytes to include the filesystem on root. (this _can_ be a partition)
4. Removes and recreates the `root` partition, the size depends on options used when starting the script.
5. Creates the `root` filesystem with the same `UUID` and `LABEL` as the system you are backing up from. (_MUST_ be `ext4`)
6. Uses `rsync` to sync both partitions. (if more than one)
-Added space is added on top of `df` reported "used space", not the size of the partition. Added space is in traditional binary system, so if you want to add 1GB, add 1024.
+Added space is added on top of `df` reported "used space", not the size of the partition. Added space is in MB, so if you want to add 1GB, add 1024.
The script can be instructed to set the img size by requesting recomended minimum size from `e2fsck` by using the `-a` option.
This is not the absolute smallest size you can achieve but is the "safest" way to create a "smallest possible" img file.
@@ -137,46 +133,31 @@ By using `-a` in combination with `-U` the script will resize the img file if ne
### Order of operations - Image update:
1. Probes the img file for information about partitions.
2. Mounts `root` partition with an offset for the loop.
-3. Checks if multiple partitions exists. If true, reads `fstab` on img file and mounts `boot` partition accordingly with an offset.
+3. Checks if multiple partitions exists. If true, reads `fstab` on img file and mounts boot partition accordingly with an offset.
4. Uses `rsync` to sync both partitions. (if more than one)
To update an existing img file simply use the `-U` option and the path to the img file.
Example: `sudo shrink-backup -U /path/to/backup.img`
-### Resizing img file when updating
+**Resizing img file when updating**
If `-a` is used in combination with `-U`, the script will compare the root partition on the img file to the size `resize2fs` recommends as minimum.
-The img file needs to be **>=256MB** smaller than `resize2fs` recommended minimum to be expanded.
-The img file needs to be **>=512MB** bigger than `resize2fs` recommended minimum to be shrunk.
-This is to protect from unnecessary resizing operations most likely not needed.
-
-**Disclaimer**
-Resizing **always** includes a small risk of corruption, please use with care (ie do not abuse). If you know your system will increase, maybe it's better to just add manual space in the creation? And then when you close in on the limit, use manual method to add more space instead of constantly using `-Ua`.
-I have ran a lot of testing of this (on "weak" arm harware like rpi4) and it rarely fails, but it _does_ happen. I also run the backups over lan so that could also be a contributing factor for the failures. Just keep that in mind. :)
+The img file needs to be **+256MB** smaller than `resize2fs` recommended minimum to be expanded.
+The img file needs to be **+512MB** bigger than `resize2fs` recommended minimum to be shrunk.
+This is to protect from unessesary resizing operations most likely not needed.
-If manually added space is used in combination with `-U`, the `root` partition on the img file will be expanded by that amount. **No checks are being performed to make sure the data you want to back up will actually fit.**
+If manually added space is used in combination with `-U`, the img file/root partition will be expanded by that amount. No checks are being performed to make sure the data you want to back up will actually fit.
Only expansion is possible with this method.
## btrfs
-**This is still in experimental stage so [ideas & feedback](https://github.com/UnconnectedBedna/shrink-backup/discussions) is HIGHLY appreciated!**
-The subvolumes are mounted with default compression: `compress=zstd` (default means `zstd:3`)
-
-I am working against Manjaro-arm to create this functionality and the standard install creates root (`/@`) and home (`/@home`) subvolumes (and some nested ones that will also be included), so the script assumes this is the situation on ALL btrfs systems as of now.
-
-The backup img is **NOT a clone**. Snapshots are NOT used to create the backup.
-The `UUID` will change on the created img filesystem (btrfs is way more picky than ext4 about this), but in the case of Manjaro (and raspberry pi too for that matter), that does not matter since `PARTUUID` is used in mounting, and that stays the same, but users should be aware.
-Subvol id:s are NOT guaranteed to be the same.
-
-Instead of using btrfs send/recieve I opted for rsync, quck and dirty.
-Both in creation of a new img and when keeping it updated with `-U`.
-My resoning for this is that this script is primarily for creating bootable img files, NOT to create perfectly cloned backups. Speed is also a strong argument here.
-
-The goal in developement of this script is ALWAYS to: as fast as possible create an img file that you can write directly to a sd-card and boot. That goal does NOT mix well with also creating a perfectly cloned backup.
-This does mean the script cares MORE about the **file integrity** rather than the **filesystem integrity**. The compression f.ex might be different than on your root filesystem. Subvol id:s might change etc etc.
-But the main goal stays the same, the backup must contain ALL REQUESTED FILES, ie a bootable file backup. I do NOT want to be responsible for people loosing their data when using this script, hence this decision. :)
+**ALL testing has been done on Manjaro-arm**
+**THIS IS NOT A CLONE, IT IS A BACKUP OF REQUIRED FILES FOR A BOOTABLE BTRFS SYSTEM!**
-All of this might change in the future though. Not the rsync part (I value speed very high), but the subvol id:s, compression and such is on my mind.
-F.ex if more subvols (or less) than root and home is used I want the script to be able to handle that.
+All options in script should work just as on `ext4`. The script will detect `btrfs` and act accordingly.
+The script will treat snapshots as nested volumes, so make sure to exclude snapshots if you have any, or directories and nested volumes will be created on the img file. This can be done in `exclude.txt`, wildcards _should_ work.
+When starting the script, the initial report window will tell you what volumes will be created. **Make sure these are correct before pressing Y**
+As of now, top level subvolumes are checked for in `/etc/fstab` and mounted accordingly, mount options should be preseved (for exmaple if you change compression).
+Autoresize function works on Manjaro-arm.
**Thank you for using my software <3**
From 0d3dc304b7591b68d4819ea8109ec6b66da5b8a2 Mon Sep 17 00:00:00 2001
From: Marcus Johansson <30673661+UnconnectedBedna@users.noreply.github.com>
Date: Sun, 28 Jan 2024 22:35:11 +0100
Subject: [PATCH 23/23] Update shrink-backup
Final update before pushing to main.
v0.9.5
---
shrink-backup | 23 ++++-------------------
1 file changed, 4 insertions(+), 19 deletions(-)
diff --git a/shrink-backup b/shrink-backup
index bfb0d1c..0c54ad3 100644
--- a/shrink-backup
+++ b/shrink-backup
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
#
# shrink-backup
-# version 0.9.5-beta
+# version 0.9.5
# backup tool for backing up and updating .img files with autoexpansion on various operating systems
#
# This program is free software: you can redistribute it and/or modify
@@ -53,17 +53,10 @@ function cleanup() {
umount "$TMP_DIR"
debug 'DEBUG' "Unmounting root partition in cleanup function: umount $TMP_DIR"
fi
- #if losetup /dev/loop0 &>/dev/null; then
if losetup "$LOOP" &>/dev/null; then
- #losetup -d /dev/loop0
losetup -d "$LOOP"
- #debug 'DEBUG' 'Removing loop0 in cleanup function: losetup -d /dev/loop0'
debug 'DEBUG' "Removing loop in cleanup function: losetup -d $LOOP"
fi
-# if losetup /dev/loop1 &>/dev/null; then
-# losetup -d /dev/loop1
-# debug 'DEBUG' 'Removing loop1 in cleanup function: losetup -d /dev/loop1'
-# fi
if [ -d "$TMP_DIR" ]; then
rm -rf "$TMP_DIR"
debug 'DEBUG' "Removing temp directory in cleanup function: rm -rf $TMP_DIR"
@@ -174,14 +167,6 @@ function debug() {
# Function to gather device information
function get_dev_variables() {
-# if [ "$FSTYPE" == 'ext4' ]; then
-# LOCAL_DEV_PTUUID=$(lsblk -lpo mountpoint,ptuuid | grep '/ ' | awk '{print $2}')
-# else
-# LOCAL_DEV_PTUUID=$(lsblk -lpo fsroots,ptuuid | grep '/ ' | awk '{print $2}')
-# fi
-# LOCAL_DEV_PATH=$(lsblk -lpo ptuuid,type,path | grep "$LOCAL_DEV_PTUUID" | grep 'disk' | awk '{print $3}')
-# debug 'DEBUG' "LOCAL_DEV_PTUUID=$LOCAL_DEV_PTUUID | LOCAL_DEV_PATH=$LOCAL_DEV_PATH"
-
# Check if separate boot and root partition exists and set variables accordingly
if [ $(lsblk | grep -c 'boot') -ne 0 ]; then
debug 'INFO' 'Separate boot partition detected'
@@ -337,14 +322,11 @@ function get_shared_variables() {
debug 'INFO' 'Separate boot partition detected'
debug 'DEBUG' "Running: cat /etc/fstab | grep '/boot' | awk '{print \$2}'"
BOOT_PATH=$(cat /etc/fstab | grep '/boot' | awk '{print $2}')
- #IMG_DEV_BOOT_PATH='/dev/loop0p1'
IMG_DEV_BOOT_PATH="${LOOP}p1"
- #IMG_DEV_ROOT_PATH='/dev/loop0p2'
IMG_DEV_ROOT_PATH="${LOOP}p2"
debug 'DEBUG' "BOOT_PATH=$BOOT_PATH | IMG_DEV_BOOT_PATH=$IMG_DEV_BOOT_PATH | IMG_DEV_ROOT_PATH=$IMG_DEV_ROOT_PATH"
else
debug 'INFO' 'No boot partition detected'
- #IMG_DEV_ROOT_PATH='/dev/loop0p1'
IMG_DEV_ROOT_PATH="${LOOP}p1"
debug 'DEBUG' "IMG_DEV_ROOT_PATH=$IMG_DEV_ROOT_PATH"
fi
@@ -874,6 +856,8 @@ function make_img() {
# Remove partition
echo '## Removing root partition...'
sleep 1
+
+ # GPT
if [ $PARTITION_TABLE == 'gpt' ]; then
echo '## GPT partition table detected, sgdisk is needed, checking if installed...'
sleep 1
@@ -926,6 +910,7 @@ function make_img() {
else
+ # MBR
debug 'INFO' 'Using sfdisk to remove root partition'
#debug 'INFO' 'Using parted to remove root partition'
debug 'DEBUG' "Running: sfdisk --delete -f $LOOP $LOCAL_ROOT_PARTN"