Skip to content

Commit a9699ab

Browse files
Improved search for backup target partitions; Enhanced "-d" parameter.
Improved automated search for backup target partitions: The script now also searches for the first partition labeled "pve_backup_usb" under /dev/disk/by-label/. Enhanced "-d" parameter: Added support for custom disk labels or UUIDs to override default locations. Multiple targets can be specified as a CSV list.
1 parent b7e871a commit a9699ab

File tree

3 files changed

+101
-24
lines changed

3 files changed

+101
-24
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88

9+
## [unreleased]
10+
11+
### Changed
12+
13+
- Improved automated search for backup target partitions: The script now also searches for the first partition labeled `pve_backup_usb` under `/dev/disk/by-label/`.
14+
15+
- Enhanced `-d` parameter: Added support for custom disk labels or UUIDs to override default locations. Multiple targets can be specified as a CSV list.
16+
17+
918
## [1.2.0] - 2024-12-07
1019

1120
### Added

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,12 @@ Explanation:
9090

9191
The script deletes the old backup content on the target device (after copying the new data if there is enough space to copy the new files and keep the old ones during copy operation or upfront if there is not enough space to keep both). To keep multiple revisions of the last `N` PVE dumps, you can use multiple external drives and rotate them as you wish (=disconnect the old drive, change and connect the new drive).
9292

93-
By default, the script uses the first partition on the first USB disk it detects in `/dev/disk/by-path/`. No worries: existing drives not [prepared](#preparation-of-an-external-usb-drive) for usage won't be destroyed nor touched as the decryption will fail. However, this automatism presumes that only one USB disk is connected during the script run. Defining a UUID will work if there are more than one USB disk attached (cf. `-d` parameter).
93+
By default, the script searches the following locations for a partition to use as the backup target for decryption and mounting:
94+
95+
1. The first partition labeled `pve_backup_usb` listed under `/dev/disk/by-label/`.
96+
2. The first partition on the first USB disk found via `/dev/disk/by-path/`.
97+
98+
No need to worry: existing partitions or drives not [intended](#preparation-of-an-external-usb-drive) for backups will not be destroyed, as decryption will simply fail, and the script will stop. If this automated behavior does not match your environment, you can provide a custom list of disk labels or UUIDs to search before the default locations are checked (cf. `-d` parameter).
9499

95100

96101
### Parameters
@@ -185,6 +190,7 @@ apt-get install parted cryptsetup
185190
parted "${TARGETDEVICE}" mktable GPT
186191
parted "${TARGETDEVICE}" mkpart primary 0% 100%
187192
cryptsetup luksFormat --cipher aes-xts-plain64 --verify-passphrase "${TARGETDEVICE}1"
193+
cryptsetup config "${TARGETDEVICE}1" --label "${DEVICELABEL}"
188194

189195
# optional: add an additional fallback key. Please use a long passphrase (at least
190196
# 20 chars) for security and store it in your password management.

pve_backup_usb.sh

Lines changed: 85 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ set -u
3333
# init
3434
opt_backupcfg_list='' # -b
3535
opt_checksums='0' # -c
36-
opt_luks_target_uuid='' # -d
36+
opt_luks_targets_list='' # -d
3737
opt_email_to='' # -e
3838
opt_email_from='' # -f
3939
opt_email_cc='' # -g
@@ -66,12 +66,12 @@ do
6666
opt_checksums='1'
6767
;;
6868

69-
# disk UUID
69+
# list of disk labels or UUIDs
7070
'd')
71-
opt_luks_target_uuid="${OPTARG}"
72-
if ! printf '%s' "${opt_luks_target_uuid}" | grep -E -q -e "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
71+
opt_luks_targets_list="${OPTARG}"
72+
if [ -z "${opt_luks_targets_list}" ]
7373
then
74-
opt_email_to=''
74+
opt_luks_targets_list=''
7575
printf '%s: Invalid value for "%s", ignoring it.\n' "$(basename "${0}")" "${opt}" 1>&2
7676
exit 2
7777
fi
@@ -179,7 +179,7 @@ USB drives, including proper logging and optional email notifications.
179179
.PP
180180
.BI "-b " "PveID[:maxCount[,PveID:maxCount[,...]]]" ""
181181
.B [-c]
182-
.BI "[-d " "UUID of a disk to decrypt" "]"
182+
.BI "[-d " "pve_backup_disk_label[,UUID[,...]]"
183183
.BI "[-e " "[email protected]" "]"
184184
.BI "[-f " "[email protected]" "]"
185185
.BI "[-g " "[email protected][,[email protected][,...]]" "]"
@@ -210,15 +210,17 @@ Enable checksum creation and verification of the copies (recommended for
210210
safety but probably doubles the time needed for completing the backup task).
211211
.TP
212212
.B -d
213-
A UUID of the target partition to decrypt. Will be used to search it in
214-
/dev/disk/by-uuid/ (you might use 'blkid /dev/sdX1' to determine the UUID).
215-
By default, the script is simply using the first partition on the first USB
216-
disk it is able to find via /dev/disk/by-path/. No worries: existing drives
217-
not used for backups won't be destroyed as the decryption will fail. But this
218-
automatism presumes that only one USB disk is connected during the
219-
script run. Defining a UUID will work if there are multiple disks (e.g. when
220-
it is not feasible in your environment to just have one disk connected
221-
simultaneously).
213+
By default, the script searches the following locations for a partition to use
214+
as the backup target for decryption and mounting:
215+
1. The first partition labeled "pve_backup_usb" listed under /dev/disk/by-label/.
216+
2. The first partition on the first USB disk found via /dev/disk/by-path/.
217+
No need to worry: existing partitions or drives not intended for backups will
218+
not be destroyed, as decryption will simply fail, and the script will stop.
219+
If this automated behavior does not match your environment, you can provide a
220+
custom list of disk labels or UUIDs to search before the default locations are
221+
checked. Separate multiple targets with commas (CSV format). Any given UUID
222+
will be searched under /dev/disk/by-uuid/, while any other string matching the
223+
pattern "^[0-9a-zA-Z_ \-]{1,16}$" will be searched under /dev/disk/by-label/.
222224
.TP
223225
.B -e
224226
Email address to send notifications to. Format: '[email protected]'.
@@ -322,12 +324,14 @@ fi
322324
IFS=',' read -r -a backupcfg_array <<< "${opt_backupcfg_list}"
323325
readonly backupcfg_array
324326

325-
if [ -z "${opt_luks_target_uuid}" ]
327+
if [ -z "${opt_luks_targets_list}" ]
326328
then
327-
readonly luks_target_uuid=""
329+
readonly luks_targets_list=""
328330
else
329-
readonly luks_target_uuid="${opt_luks_target_uuid}"
331+
readonly luks_targets_list="${opt_luks_targets_list}"
330332
fi
333+
IFS=',' read -r -a luks_targets_array <<< "${luks_targets_list}"
334+
readonly luks_targets_array
331335

332336
if [ -z "${opt_backup_user}" ]
333337
then
@@ -796,14 +800,72 @@ then
796800
fi
797801

798802

799-
# determine target device
803+
# determine target device partition
800804
luks_target=""
801-
if [ -n "${luks_target_uuid}" ]
805+
message="Searching for target partition at"
806+
for luks_target in "${luks_targets_array[@]}"
807+
do
808+
# UUID of a partition
809+
if [ -n "${luks_target}" ] &&
810+
printf '%s' "${luks_target}" | grep -E -q -e "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
811+
then
812+
luks_target="/dev/disk/by-uuid/${luks_target}"
813+
if [ -L "${luks_target}" ]
814+
then
815+
message "${message} '${luks_target}'... found."
816+
break 1
817+
else
818+
message "${message} '${luks_target}'... not found, continuing."
819+
fi
820+
821+
# label of a partition
822+
elif [ -n "${luks_target}" ] &&
823+
printf '%s' "${luks_target}" | grep -E -q -e "^[0-9a-zA-Z_ \-]{1,16}$"
824+
then
825+
luks_target="/dev/disk/by-label/${luks_target}"
826+
if [ -L "${luks_target}" ]
827+
then
828+
message "${message} '${luks_target}'... found."
829+
break 1
830+
else
831+
message "${message} '${luks_target}'... not found, continuing."
832+
fi
833+
834+
# invalid value
835+
elif [ -n "${luks_target}" ]
836+
then
837+
message "Invalid value '${luks_target}' (has to be a valid partition label or UUID, check '-d' parameter), continuing." "warning"
838+
fi
839+
840+
# nothing was found (yet)
841+
luks_target=""
842+
done
843+
# use the first partition with a "pve_backup_usb" label if no (useable) target was specified or found
844+
if [ -z "${luks_target}" ]
802845
then
803-
luks_target="/dev/disk/by-uuid/${luks_target_uuid}"
804-
else
846+
luks_target="/dev/disk/by-label/pve_backup_usb"
847+
if [ -L "${luks_target}" ]
848+
then
849+
message "${message} '${luks_target}'... found."
850+
else
851+
message "${message} '${luks_target}'... not found, continuing."
852+
fi
853+
fi
854+
# use the first partition of the first usb storage device if no (useable) target was specified or found
855+
if [ -z "${luks_target}" ]
856+
then
857+
805858
luks_target="/dev/$(ls -l /dev/disk/by-path/*usb*part1 | cut -f 7 -d "/" | head -n 1)"
859+
if [ -b "${luks_target}" ]
860+
then
861+
message "${message} '${luks_target}'... found."
862+
else
863+
message "${message} '${luks_target}'... not found."
864+
endScript "Could not determine any target partition for decryption (backup storage device available?)." "error"
865+
exit 1 # endScript should exit, this is just a fallback
866+
fi
806867
fi
868+
unset message
807869

808870

809871
# unlock target device
@@ -1097,7 +1159,7 @@ do
10971159
if [ $exitcode_sha1sum -ne 0 ]
10981160
then
10991161
errors_during_backup="1"
1100-
message="Creating checksums file failed with exit code $exitcode_sha1sum."
1162+
message="Creating checksums file failed with exit code ${exitcode_sha1sum}."
11011163
# continue on error
11021164
if [ "${opt_continue_on_backuperror}" = "1" ]
11031165
then

0 commit comments

Comments
 (0)