better dry-run handling, separate "--copy" option.
This commit is contained in:
@@ -20,7 +20,7 @@
|
|||||||
#
|
#
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
# Duplicate SRC disk partitions to same structured DST disk ones.
|
# Duplicate SRC disk partitions to same structured DST disk ones.
|
||||||
# if SRC is omitted, tue running system disk (where root partition
|
# if SRC is omitted, the running system disk (where root partition
|
||||||
# resides) will be used.
|
# resides) will be used.
|
||||||
# Both SRC and DST *must* have same partition base LABELs - as 'LABEL'
|
# Both SRC and DST *must* have same partition base LABELs - as 'LABEL'
|
||||||
# field for lsblk(1) and blkid(1), with an ending character (unique per
|
# field for lsblk(1) and blkid(1), with an ending character (unique per
|
||||||
@@ -31,8 +31,17 @@
|
|||||||
# must be 'root2', 'export2, and 'swap2'.
|
# must be 'root2', 'export2, and 'swap2'.
|
||||||
#
|
#
|
||||||
# OPTIONS
|
# OPTIONS
|
||||||
# -d, -n, --dry-run, --no
|
# -a, --autofs=DIR
|
||||||
# Dry-run: nothing will be written to disk.
|
# Use DIR as autofs "LABEL-based" automount. See AUTOFS below. Default
|
||||||
|
# is /mnt.
|
||||||
|
#
|
||||||
|
# -c, --copy=ACTION
|
||||||
|
# ACTION can be 'yes' (all eligible partitions will be copied), 'no'
|
||||||
|
# (no partition will be copied), or 'ask' (will ask for all eligible
|
||||||
|
# partitions). Default is 'no'.
|
||||||
|
#
|
||||||
|
# -d, --dry-run
|
||||||
|
# Dry-run: nothing will be really be done.
|
||||||
#
|
#
|
||||||
# -g, --grub
|
# -g, --grub
|
||||||
# Install grub on destination disk.
|
# Install grub on destination disk.
|
||||||
@@ -52,10 +61,6 @@
|
|||||||
# Mandatory if SRC is provided, forbidden otherwise.
|
# Mandatory if SRC is provided, forbidden otherwise.
|
||||||
# PARTNUM is root partition number on SRC disk.
|
# PARTNUM is root partition number on SRC disk.
|
||||||
#
|
#
|
||||||
# -y, --yes
|
|
||||||
# Do not ask for actions confirmation. Default is to display next
|
|
||||||
# action and ask user to [y] do it, [q] quit, [s] skip.
|
|
||||||
#
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
# Copy sda to sdb, root partition is partition (sda1/sdb1)
|
# Copy sda to sdb, root partition is partition (sda1/sdb1)
|
||||||
# $ sudo dup-live-disk.sh --root 1 sda sdb
|
# $ sudo dup-live-disk.sh --root 1 sda sdb
|
||||||
@@ -92,16 +97,17 @@ Usage: $CMD [OPTIONS] [SRC] DST
|
|||||||
Duplicate SRC (or live system) disk partitions to DST disk partitions.
|
Duplicate SRC (or live system) disk partitions to DST disk partitions.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-d, -n, --dry-run, --no dry-run: nothing will be written to disk
|
-a, --autofs=DIR autofs "LABEL-based" directory. Default is '/mnt'.
|
||||||
-g, --grub install grub on destination disk
|
-c, --copy=ACTION do partitions copies ('yes'), do not copy then ('no')
|
||||||
-h, --help this help
|
or ask for each of them ('ask'). Default is 'no'.
|
||||||
-m, --man display a "man-like" page and exit
|
-d, --dry-run dry-run: nothing will be written to disk
|
||||||
--mariadb stop and restart mysql/mariadb server before and
|
-g, --grub install grub on destination disk
|
||||||
after copies
|
-h, --help this help
|
||||||
-r, --root=PARTNUM root partition number on SRC device
|
-m, --man display a "man-like" page and exit
|
||||||
mandatory if and only if SRC is provided
|
--mariadb stop and restart mysql/mariadb server before and
|
||||||
-y, --yes DANGER ! perform all actions without user
|
after copies
|
||||||
confirmation
|
-r, --root=PARTNUM root partition number on SRC device
|
||||||
|
mandatory if and only if SRC is provided
|
||||||
|
|
||||||
SRC and DST have strong constraints on partitions schemes and naming.
|
SRC and DST have strong constraints on partitions schemes and naming.
|
||||||
Type '$CMD --man" for more details"
|
Type '$CMD --man" for more details"
|
||||||
@@ -112,19 +118,19 @@ _EOF
|
|||||||
# mariadb start/stop
|
# mariadb start/stop
|
||||||
function mariadb_maybe_stop {
|
function mariadb_maybe_stop {
|
||||||
if [[ $MARIADB == yes ]] && systemctl is-active --quiet mysql; then
|
if [[ $MARIADB == yes ]] && systemctl is-active --quiet mysql; then
|
||||||
log -n "stopping mariadb/mysql... "
|
#log -n "stopping mariadb/mysql... "
|
||||||
systemctl stop mariadb
|
echorun systemctl stop mariadb
|
||||||
# bug if script stops here
|
# bug if script stops here
|
||||||
MARIADBSTOPPED=yes
|
MARIADBSTOPPED=yes
|
||||||
log "done."
|
#log "done."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
function mariadb_maybe_start {
|
function mariadb_maybe_start {
|
||||||
if [[ $MARIADB == yes && $MARIADBSTOPPED == yes ]]; then
|
if [[ $MARIADB == yes && $MARIADBSTOPPED == yes ]]; then
|
||||||
log -n "restarting mariadb/mysql... "
|
#log -n "restarting mariadb/mysql... "
|
||||||
systemctl start mariadb
|
echorun systemctl start mariadb
|
||||||
MARIADBSTOPPED=no
|
MARIADBSTOPPED=no
|
||||||
log "done."
|
#log "done."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,9 +161,12 @@ function log {
|
|||||||
|
|
||||||
# prints out and run a command.
|
# prints out and run a command.
|
||||||
function echorun {
|
function echorun {
|
||||||
log "%s" "$@"
|
if [[ "$DRYRUN" == 'yes' ]]; then
|
||||||
"$@"
|
log "%s " "dry-run: " "$@"
|
||||||
return $?
|
else
|
||||||
|
log "%s " "$@"
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function error_handler {
|
function error_handler {
|
||||||
@@ -168,15 +177,19 @@ function error_handler {
|
|||||||
trap 'error_handler $LINENO $?' ERR SIGHUP SIGINT SIGTERM
|
trap 'error_handler $LINENO $?' ERR SIGHUP SIGINT SIGTERM
|
||||||
|
|
||||||
function exit_handler {
|
function exit_handler {
|
||||||
|
local mnt
|
||||||
|
|
||||||
log "exit handler (at line $1)"
|
log "exit handler (at line $1)"
|
||||||
mariadb_maybe_start
|
mariadb_maybe_start
|
||||||
if [[ -v DSTMNT ]]; then
|
if [[ -n "$DSTMNT" ]] && mountpoint -q "$DSTMNT"; then
|
||||||
umount "$DSTMNT/dev"
|
for mnt in "$DSTMNT"/{dev,proc,sys}; do
|
||||||
umount "$DSTMNT/proc"
|
if mountpoint -q "$mnt"; then
|
||||||
umount "$DSTMNT/sys"
|
echorun umount "$mnt"
|
||||||
|
fi
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trap 'exit_handler $LINENO' EXIT
|
trap 'exit_handler $LINENO' EXIT
|
||||||
|
|
||||||
function check_block_device {
|
function check_block_device {
|
||||||
@@ -237,14 +250,16 @@ SRC=""
|
|||||||
DST=""
|
DST=""
|
||||||
SRCROOT=""
|
SRCROOT=""
|
||||||
ROOTPARTNUM=""
|
ROOTPARTNUM=""
|
||||||
DOIT=manual
|
|
||||||
MARIADB=no
|
DRYRUN=no # dry-run
|
||||||
MARIADBSTOPPED=no
|
GRUB=no # install grub
|
||||||
GRUBINSTALL=no
|
COPY=no # do FS copies
|
||||||
|
MARIADB=no # stop/start mysql/mariadb
|
||||||
|
MARIADBSTOPPED=no # mysql stopped ?
|
||||||
|
|
||||||
# short and long options
|
# short and long options
|
||||||
SOPTS="dnghmr:y"
|
SOPTS="c:dghmr:"
|
||||||
LOPTS="dry-run,no,grub,help,man,mariadb,root:,yes"
|
LOPTS="copy:,dry-run,grub,help,man,mariadb,root:"
|
||||||
|
|
||||||
if ! TMP=$(getopt -o "$SOPTS" -l "$LOPTS" -n "$CMD" -- "$@"); then
|
if ! TMP=$(getopt -o "$SOPTS" -l "$LOPTS" -n "$CMD" -- "$@"); then
|
||||||
log "Use '$CMD --help' or '$CMD --man' for help."
|
log "Use '$CMD --help' or '$CMD --man' for help."
|
||||||
@@ -256,14 +271,22 @@ unset TMP
|
|||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
'-d'|'-n'|'--dry-run'|'--no')
|
'-c'|'--copy')
|
||||||
DOIT=no
|
case "$2" in
|
||||||
|
"no") COPY=no;;
|
||||||
|
"yes") COPY=yes;;
|
||||||
|
"ask") COPY=ask;;
|
||||||
|
*) log "invalid '$2' --copy flag"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
shift
|
shift
|
||||||
continue
|
;;
|
||||||
|
'-d'|'--dry-run')
|
||||||
|
DRYRUN=yes
|
||||||
;;
|
;;
|
||||||
'-g'|'--grub')
|
'-g'|'--grub')
|
||||||
GRUBINSTALL=yes
|
GRUB=yes
|
||||||
shift
|
|
||||||
;;
|
;;
|
||||||
'-h'|'--help')
|
'-h'|'--help')
|
||||||
usage
|
usage
|
||||||
@@ -275,7 +298,6 @@ while true; do
|
|||||||
;;
|
;;
|
||||||
'--mariadb')
|
'--mariadb')
|
||||||
MARIADB=yes
|
MARIADB=yes
|
||||||
shift
|
|
||||||
;;
|
;;
|
||||||
'-r'|'--root')
|
'-r'|'--root')
|
||||||
ROOTPARTNUM="$2"
|
ROOTPARTNUM="$2"
|
||||||
@@ -283,13 +305,7 @@ while true; do
|
|||||||
log "$CMD: $ROOTPARTNUM must be a partition number."
|
log "$CMD: $ROOTPARTNUM must be a partition number."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
shift 2
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
'-y'|'--yes')
|
|
||||||
DOIT=yes
|
|
||||||
shift
|
shift
|
||||||
continue
|
|
||||||
;;
|
;;
|
||||||
'--')
|
'--')
|
||||||
shift
|
shift
|
||||||
@@ -301,9 +317,9 @@ while true; do
|
|||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
case "$#" in
|
case "$#" in
|
||||||
1)
|
1)
|
||||||
if [[ -n "$ROOTPARTNUM" ]]; then
|
if [[ -n "$ROOTPARTNUM" ]]; then
|
||||||
@@ -355,7 +371,7 @@ declare -a LABELS=(${SRCLABELS[@]%?})
|
|||||||
#log "LABELS=${#LABELS[@]} - ${LABELS[*]}"
|
#log "LABELS=${#LABELS[@]} - ${LABELS[*]}"
|
||||||
|
|
||||||
|
|
||||||
declare -a SRCDEVS SRCFS SRCDOIT
|
declare -a SRCDEVS SRCFS SRC_VALID_FS
|
||||||
# ... and corresponding partition device and fstype
|
# ... and corresponding partition device and fstype
|
||||||
for ((i=0; i<${#LABELS[@]}; ++i)); do
|
for ((i=0; i<${#LABELS[@]}; ++i)); do
|
||||||
TMP="${LABELS[$i]}$SRCCHAR"
|
TMP="${LABELS[$i]}$SRCCHAR"
|
||||||
@@ -365,8 +381,8 @@ for ((i=0; i<${#LABELS[@]}; ++i)); do
|
|||||||
log "found LABEL=$TMP DEV=$TMPDEV FSTYPE=$TMPFS"
|
log "found LABEL=$TMP DEV=$TMPDEV FSTYPE=$TMPFS"
|
||||||
SRCDEVS[$i]="$TMPDEV"
|
SRCDEVS[$i]="$TMPDEV"
|
||||||
SRCFS[$i]="$TMPFS"
|
SRCFS[$i]="$TMPFS"
|
||||||
SRCDOIT[$i]=n
|
SRC_VALID_FS[$i]=n
|
||||||
in_array "$TMPFS" VALIDFS && SRCDOIT[$i]=y
|
in_array "$TMPFS" VALIDFS && SRC_VALID_FS[$i]=y
|
||||||
unset TMP TMPDEV TMPFS
|
unset TMP TMPDEV TMPFS
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -386,9 +402,8 @@ fi
|
|||||||
# log "ROOTLABEL=$ROOTLABEL"
|
# log "ROOTLABEL=$ROOTLABEL"
|
||||||
# log "SRCROOTLABEL=%s DSTROOTLABEL=%s" "$SRCROOTLABEL" "$DSTROOTLABEL"
|
# log "SRCROOTLABEL=%s DSTROOTLABEL=%s" "$SRCROOTLABEL" "$DSTROOTLABEL"
|
||||||
# log "SRCCHAR=%s DSTCHAR=%s" "$SRCCHAR" "$DSTCHAR"
|
# log "SRCCHAR=%s DSTCHAR=%s" "$SRCCHAR" "$DSTCHAR"
|
||||||
# log "DOIT=%s\n" "$DOIT"
|
|
||||||
|
|
||||||
declare -a DSTLABELS DSTDEVS DSTFS DSTDOIT
|
declare -a DSTLABELS DSTDEVS DSTFS DST_VALID_FS
|
||||||
# Do the same for correponding DST partitions labels, device, and fstype
|
# Do the same for correponding DST partitions labels, device, and fstype
|
||||||
for ((i=0; i<${#LABELS[@]}; ++i)); do
|
for ((i=0; i<${#LABELS[@]}; ++i)); do
|
||||||
TMP="${LABELS[$i]}$DSTCHAR"
|
TMP="${LABELS[$i]}$DSTCHAR"
|
||||||
@@ -408,8 +423,8 @@ for ((i=0; i<${#LABELS[@]}; ++i)); do
|
|||||||
DSTLABELS[$i]="$TMP"
|
DSTLABELS[$i]="$TMP"
|
||||||
DSTDEVS[$i]="$TMPDEV"
|
DSTDEVS[$i]="$TMPDEV"
|
||||||
DSTFS[$i]="$TMPFS"
|
DSTFS[$i]="$TMPFS"
|
||||||
DSTDOIT[$i]=n
|
DST_VALID_FS[$i]=n
|
||||||
in_array "$TMPFS" VALIDFS && DSTDOIT[$i]=y
|
in_array "$TMPFS" VALIDFS && DST_VALID_FS[$i]=y
|
||||||
unset TMP TMPDEV TMPFS
|
unset TMP TMPDEV TMPFS
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -417,56 +432,47 @@ for ((i=0; i<${#LABELS[@]}; ++i)); do
|
|||||||
log -n "%s %s " "${SRCDEVS[$i]}" "${DSTDEVS[$i]}"
|
log -n "%s %s " "${SRCDEVS[$i]}" "${DSTDEVS[$i]}"
|
||||||
log -n "%s %s " "${SRCLABELS[$i]}" "${DSTLABELS[$i]}"
|
log -n "%s %s " "${SRCLABELS[$i]}" "${DSTLABELS[$i]}"
|
||||||
log -n "%s %s " "${SRCFS[$i]}" "${DSTFS[$i]}"
|
log -n "%s %s " "${SRCFS[$i]}" "${DSTFS[$i]}"
|
||||||
log -n "%s %s " "${SRCDOIT[$i]}" "${DSTDOIT[$i]}"
|
log -n "%s %s " "${SRC_VALID_FS[$i]}" "${DST_VALID_FS[$i]}"
|
||||||
[[ "$DSTROOTLABEL" == "${DSTLABELS[$i]}" ]] && log "*"
|
[[ "$DSTROOTLABEL" == "${DSTLABELS[$i]}" ]] && log "*"
|
||||||
echo
|
echo
|
||||||
done | column -N DEV1,DEV2,LABEL1,LABEL2,FS1,FS2,SDOIT,DDOIT,ROOT -t -o " | "
|
done | column -N DEV1,DEV2,LABEL1,LABEL2,FS1,FS2,SVALID\?,DVALID\?,ROOT -t -o " | "
|
||||||
|
|
||||||
RSYNCOPTS="-axH --delete --delete-excluded"
|
RSYNCOPTS="-axH --delete --delete-excluded"
|
||||||
FILTER=--filter="dir-merge .rsync-disk-copy"
|
FILTER=--filter="dir-merge .rsync-disk-copy"
|
||||||
# copy loop
|
# copy loop
|
||||||
for ((i=0; i<${#LABELS[@]}; ++i)); do
|
for ((i=0; i<${#LABELS[@]}; ++i)); do
|
||||||
if [[ "${SRCDOIT[$i]}" != y ]] || [[ "${DSTDOIT[$i]}" != y ]]; then
|
if [[ "${SRC_VALID_FS[$i]}" != y ]] || [[ "${DST_VALID_FS[$i]}" != y ]]; then
|
||||||
log "skipping label %s" "${LABELS[$i]}"
|
log "skipping label %s" "${LABELS[$i]}"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
SRCPART=/mnt/${SRCLABELS[$i]}/
|
SRCPART=/mnt/${SRCLABELS[$i]}/
|
||||||
DSTPART=/mnt/${DSTLABELS[$i]}
|
DSTPART=/mnt/${DSTLABELS[$i]}
|
||||||
|
|
||||||
log -n "%s -> %s : " "$SRCPART" "$DSTPART"
|
#log -n "%s -> %s : " "$SRCPART" "$DSTPART"
|
||||||
#log "\t%s %s %s %s %s" rsync "${RSYNCOPTS}" "$FILTER" "$SRCPART" "$DSTPART"
|
#log "\t%s %s %s %s %s" rsync "${RSYNCOPTS}" "$FILTER" "$SRCPART" "$DSTPART"
|
||||||
skip=y
|
copy="$COPY"
|
||||||
case "$DOIT" in
|
if [[ "$COPY" == 'ask' ]]; then
|
||||||
yes)
|
yesno "Copy $SRCPART to $DSTPART ? [y/n/q]" && copy=yes || copy=no
|
||||||
skip=n
|
fi
|
||||||
;;
|
if [[ "$copy" == yes ]]; then
|
||||||
no)
|
|
||||||
log "skipping (dry run)."
|
|
||||||
;;
|
|
||||||
manual)
|
|
||||||
yesno "proceed ? [y/n/q]" && skip=n
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
if [[ "$skip" == n ]]; then
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
mariadb_maybe_stop
|
mariadb_maybe_stop
|
||||||
|
# shellcheck disable=SC2086
|
||||||
echorun rsync "$FILTER" ${RSYNCOPTS} "$SRCPART" "$DSTPART"
|
echorun rsync "$FILTER" ${RSYNCOPTS} "$SRCPART" "$DSTPART"
|
||||||
fi
|
fi
|
||||||
log ""
|
#log ""
|
||||||
done
|
done
|
||||||
|
|
||||||
# grub install
|
# grub install
|
||||||
# mount virtual devices
|
if [[ "$GRUB" == yes ]]; then
|
||||||
if [[ $GRUBINSTALL == yes ]]; then
|
|
||||||
log "installing grub on $DST..."
|
log "installing grub on $DST..."
|
||||||
DSTMNT="/mnt/$DSTROOTLABEL"
|
DSTMNT="/mnt/$DSTROOTLABEL"
|
||||||
mount -o bind /sys "$DSTMNT/sys"
|
# mount virtual devices
|
||||||
mount -o bind /proc "$DSTMNT/proc"
|
echorun mount -o bind /sys "$DSTMNT/sys"
|
||||||
mount -o bind /dev "$DSTMNT/dev"
|
echorun mount -o bind /proc "$DSTMNT/proc"
|
||||||
|
echorun mount -o bind /dev "$DSTMNT/dev"
|
||||||
chroot "$DSTMNT" update-grub
|
|
||||||
chroot "$DSTMNT" grub-install "$DST"
|
|
||||||
|
|
||||||
|
echorun chroot "$DSTMNT" update-grub
|
||||||
|
echorun chroot "$DSTMNT" grub-install "$DST"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
Reference in New Issue
Block a user