Add grub management / remove old dead code.

This commit is contained in:
2021-04-28 10:47:11 +02:00
parent 0cc121eb89
commit 9b3fb864cd

View File

@@ -20,26 +20,34 @@
# #
# 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 resides) will # if SRC is omitted, tue running system disk (where root partition
# be used. # resides) will be used.
# Both SRC and DST *must* have same partition base LABELs - as 'LABEL' field for # Both SRC and DST *must* have same partition base LABELs - as 'LABEL'
# lsblk(1) and blkid(1), with an ending character (unique per disk) to # field for lsblk(1) and blkid(1), with an ending character (unique per
# differentiate them. # disk) to differentiate them.
# For example, if partitions base labels are 'root', 'export', and 'swap', # For example, if partitions base labels are 'root', 'export', and 'swap',
# SRC disk the ending character '1' and DST disk the character '2', SRC # SRC disk the ending character '1' and DST disk the character '2', SRC
# partitions must be 'root1', 'export1, and 'swap1', and DST partitions must be # partitions must be 'root1', 'export1, and 'swap1', and DST partitions
# 'root2', 'export2, and 'swap2'. # must be 'root2', 'export2, and 'swap2'.
# #
# OPTIONS # OPTIONS
# -d, -n, --dry-run, --no # -d, -n, --dry-run, --no
# Dry-run: nothing will be written to disk. # Dry-run: nothing will be written to disk.
# #
# -g, --grub
# Install grub on destination disk.
# Warning: Only works if root partition contains all necessary for
# grub: /boot, /usr, etc...
#
# -h, --help # -h, --help
# Display short help and exit. # Display short help and exit.
# #
# -m, --man # -m, --man
# Display a "man-like" description and exit. # Display a "man-like" description and exit.
# #
# --mariadb
# Stop mysql/mariadb before effective copies, restart after.
#
# -r, --root=PARTNUM # -r, --root=PARTNUM
# 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.
@@ -61,16 +69,18 @@
# don't use it if you don't *fully* understand it. # don't use it if you don't *fully* understand it.
# #
# TODO # TODO
# Write about autofs. # Write about autofs configuration.
# Log levels
# Separate dry-run and copies/mysql/grub
#%MAN_END% #%MAN_END%
# command line # command line
SCRIPT="${0}" SCRIPT="$0"
CMD="${0##*/}" CMD="${0##*/}"
# valid filesystems # valid filesystems
# shellcheck disable=2034 # shellcheck disable=2034
VALIDFS=(ext3 ext4 btrfs vfat reiserfs) VALIDFS=(ext3 ext4 btrfs vfat reiserfs xfs zfs)
function man { function man {
sed -n '/^#%MAN_BEGIN%/,/^#%MAN_END%$/{//!p}' "$SCRIPT" | sed -E 's/^# ?//' sed -n '/^#%MAN_BEGIN%/,/^#%MAN_END%$/{//!p}' "$SCRIPT" | sed -E 's/^# ?//'
@@ -83,8 +93,11 @@ 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 -d, -n, --dry-run, --no dry-run: nothing will be written to disk
-g, --grub install grub on destination disk
-h, --help this help -h, --help this help
-m, --man display a "man-like" page and exit -m, --man display a "man-like" page and exit
--mariadb stop and restart mysql/mariadb server before and
after copies
-r, --root=PARTNUM root partition number on SRC device -r, --root=PARTNUM root partition number on SRC device
mandatory if and only if SRC is provided mandatory if and only if SRC is provided
-y, --yes DANGER ! perform all actions without user -y, --yes DANGER ! perform all actions without user
@@ -96,6 +109,25 @@ _EOF
exit 0 exit 0
} }
# mariadb start/stop
function mariadb_maybe_stop {
if [[ $MARIADB == yes ]] && systemctl is-active --quiet mysql; then
log -n "stopping mariadb/mysql... "
systemctl stop mariadb
# bug if script stops here
MARIADBSTOPPED=yes
log "done."
fi
}
function mariadb_maybe_start {
if [[ $MARIADB == yes && $MARIADBSTOPPED == yes ]]; then
log -n "restarting mariadb/mysql... "
systemctl start mariadb
MARIADBSTOPPED=no
log "done."
fi
}
# log function # log function
# parameters: # parameters:
# -l, -s: long, or short prefix (default: none). Last one is used. # -l, -s: long, or short prefix (default: none). Last one is used.
@@ -115,6 +147,7 @@ function log {
done done
[[ $prefix != "" ]] && printf "%s " "$prefix" [[ $prefix != "" ]] && printf "%s " "$prefix"
printf "%s" "$timestr" printf "%s" "$timestr"
# shellcheck disable=SC2059
printf "$@" printf "$@"
[[ $newline = y ]] && printf "\n" [[ $newline = y ]] && printf "\n"
return 0 return 0
@@ -134,21 +167,33 @@ function error_handler {
} }
trap 'error_handler $LINENO $?' ERR SIGHUP SIGINT SIGTERM trap 'error_handler $LINENO $?' ERR SIGHUP SIGINT SIGTERM
function exit_handler {
log "exit handler (at line $1)"
mariadb_maybe_start
if [[ -v DSTMNT ]]; then
umount "$DSTMNT/dev"
umount "$DSTMNT/proc"
umount "$DSTMNT/sys"
fi
}
trap 'exit_handler $LINENO' EXIT
function check_block_device { function check_block_device {
local devtype="$1" local devtype="$1"
local mode="$2" local mode="$2"
local dev="$3" local dev="$3"
if [[ ! -b "$dev" ]]; then if [[ ! -b "$dev" ]]; then
log "$CMD: $devtype '$dev' is not a block device." >&2 log "$CMD: $devtype '$dev' is not a block device."
exit 1 exit 1
fi fi
if [[ ! -r "$dev" ]]; then if [[ ! -r "$dev" ]]; then
log "$CMD: $devtype '$dev' is not readable." >&2 log "$CMD: $devtype '$dev' is not readable."
exit 1 exit 1
fi fi
if [[ $mode = "w" && ! -w "$dev" ]]; then if [[ $mode = "w" && ! -w "$dev" ]]; then
log "$CMD: $devtype '$dev' is not writable." >&2 log "$CMD: $devtype '$dev' is not writable."
exit 1 exit 1
fi fi
return 0 return 0
@@ -164,25 +209,47 @@ function in_array {
return 1 return 1
} }
# get y/n/q user input
function yesno {
local input
while true; do
printf "%s " "$1"
read -r input
case "$input" in
y|Y)
return 0
;;
q|Q)
log "aborting..."
exit 0
;;
n|N)
return 1
;;
*)
printf "invalid answer. "
esac
done
}
# source and destination devices, root partition # source and destination devices, root partition
SRC="" SRC=""
DST="" DST=""
SRCROOT="" SRCROOT=""
ROOTPARTNUM="" ROOTPARTNUM=""
DOIT=manual DOIT=manual
MARIADB=no
MARIADBSTOPPED=no
GRUBINSTALL=no
# short and long options # short and long options
SOPTS="dnhmr:y" SOPTS="dnghmr:y"
LOPTS="dry-run,no,help,man,root:,yes" LOPTS="dry-run,no,grub,help,man,mariadb,root:,yes"
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."
exit 1 exit 1
fi fi
# if (( $? > 1 )); then
# echo 'Terminating...' >&2
# exit 1
# fi
eval set -- "$TMP" eval set -- "$TMP"
unset TMP unset TMP
@@ -194,6 +261,10 @@ while true; do
shift shift
continue continue
;; ;;
'-g'|'--grub')
GRUBINSTALL=yes
shift
;;
'-h'|'--help') '-h'|'--help')
usage usage
exit 0 exit 0
@@ -202,10 +273,14 @@ while true; do
man man
exit 0 exit 0
;; ;;
'--mariadb')
MARIADB=yes
shift
;;
'-r'|'--root') '-r'|'--root')
ROOTPARTNUM="$2" ROOTPARTNUM="$2"
if ! [[ "$ROOTPARTNUM" =~ ^[[:digit:]]+$ ]]; then if ! [[ "$ROOTPARTNUM" =~ ^[[:digit:]]+$ ]]; then
log "$CMD: $ROOTPARTNUM must be a partition number." >&2 log "$CMD: $ROOTPARTNUM must be a partition number."
exit 1 exit 1
fi fi
shift 2 shift 2
@@ -222,7 +297,7 @@ while true; do
;; ;;
*) *)
usage usage
log 'Internal error!' >&2 log 'Internal error!'
exit 1 exit 1
;; ;;
esac esac
@@ -232,8 +307,8 @@ done
case "$#" in case "$#" in
1) 1)
if [[ -n "$ROOTPARTNUM" ]]; then if [[ -n "$ROOTPARTNUM" ]]; then
log "$CMD: cannot have --root option for live system." >&2 log "$CMD: cannot have --root option for live system."
log "Use '$CMD --help' or '$CMD --man' for help." >&2 log "Use '$CMD --help' or '$CMD --man' for help."
exit 1 exit 1
fi fi
# guess root partition disk name # guess root partition disk name
@@ -244,8 +319,8 @@ case "$#" in
;; ;;
2) 2)
if [[ -z "$ROOTPARTNUM" ]]; then if [[ -z "$ROOTPARTNUM" ]]; then
log "$CMD: missing --root option for non live system." >&2 log "$CMD: missing --root option for non live system."
log "Use '$CMD --help' or '$CMD --man' for help." >&2 log "Use '$CMD --help' or '$CMD --man' for help."
exit 1 exit 1
fi fi
SRC="/dev/$1" SRC="/dev/$1"
@@ -253,7 +328,7 @@ case "$#" in
DST="/dev/$2" DST="/dev/$2"
;; ;;
*) *)
usage >&2 usage
exit 1 exit 1
esac esac
@@ -295,7 +370,6 @@ for ((i=0; i<${#LABELS[@]}; ++i)); do
unset TMP TMPDEV TMPFS unset TMP TMPDEV TMPFS
done done
DSTROOT="$DST$ROOTPARTNUM" DSTROOT="$DST$ROOTPARTNUM"
check_block_device "destination root partition" w "$DSTROOT" check_block_device "destination root partition" w "$DSTROOT"
DSTROOTLABEL=$(lsblk -no label "$DSTROOT") DSTROOTLABEL=$(lsblk -no label "$DSTROOT")
@@ -338,14 +412,15 @@ for ((i=0; i<${#LABELS[@]}; ++i)); do
in_array "$TMPFS" VALIDFS && DSTDOIT[$i]=y in_array "$TMPFS" VALIDFS && DSTDOIT[$i]=y
unset TMP TMPDEV TMPFS unset TMP TMPDEV TMPFS
done done
echo ZOB "${SRCDEVS[0]}" "${DSTDEVS[0]}"
for ((i=0; i<${#LABELS[@]}; ++i)); do 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 "%s %s" "${SRCDOIT[$i]}" "${DSTDOIT[$i]}" log -n "%s %s " "${SRCDOIT[$i]}" "${DSTDOIT[$i]}"
[[ "$DSTROOTLABEL" == "${DSTLABELS[$i]}" ]] && log "*"
echo echo
done | column -N DEV1,DEV2,LABEL1,LABEL2,FS1,FS2,SDOIT,DDOIT -t -o " | " done | column -N DEV1,DEV2,LABEL1,LABEL2,FS1,FS2,SDOIT,DDOIT,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"
@@ -369,104 +444,29 @@ for ((i=0; i<${#LABELS[@]}; ++i)); do
log "skipping (dry run)." log "skipping (dry run)."
;; ;;
manual) manual)
log -n "proceed ? [y/N/q] " yesno "proceed ? [y/n/q]" && skip=n
read -r key
case "$key" in
y|Y)
log "copying..."
skip=n
;; ;;
q|Q)
log "aborting..."
exit 0
;;
n|N|*)
log "skipping..."
;;
esac
esac esac
if [[ "$skip" == n ]]; then if [[ "$skip" == n ]]; then
# shellcheck disable=SC2086 # shellcheck disable=SC2086
mariadb_maybe_stop
echorun rsync "$FILTER" ${RSYNCOPTS} "$SRCPART" "$DSTPART" echorun rsync "$FILTER" ${RSYNCOPTS} "$SRCPART" "$DSTPART"
fi fi
log "" log ""
done done
exit 0
# array of partitions to copy
TO_COPY=(root export EFI)
# An alternative to SRCNUM, DSTNUM, and TO_COPY variables would be to have
# an array containing src and destination partitions:
# (partsrc1 partdst1 partsrc2 partdst2 etc...)
# example:
# TO_COPY=(root2 root1 export2 export1)
# declare -i i
# for ((i=0; i<${#TO_COPY[@]}; i+=2)); do
# SRC=${#TO_COPY[$i]}
# DST=${#TO_COPY[$i + 1]}
# etc...
# where we will configure/install grub: mount point, device
GRUB_ROOT=/mnt/root${DSTNUM}
GRUB_DEV=/dev/$(lsblk -no pkname /dev/disk/by-label/root${DSTNUM})
# we will use ".rsync-disk-copy" files to exclude files/dirs
# stop what could be problematic (databases, etc...)
systemctl stop mysql
# partitions copy
for part in ${TO_COPY[@]}; do
SRCPART=/mnt/${part}${SRCNUM}/
DSTPART=/mnt/${part}${DSTNUM}
echo copy from $SRCPART to $DSTPART
echo -n "press a key to continue..."
read -r key
echo rsync ${RSYNCOPTS} "$FILTER" "$SRCPART" "$DSTPART"
rsync ${RSYNCOPTS} "$FILTER" "$SRCPART" "$DSTPART"
done
# grub install # grub install
# mount virtual devices # mount virtual devices
mount -o bind /sys ${GRUB_ROOT}/sys if [[ $GRUBINSTALL == yes ]]; then
mount -o bind /proc ${GRUB_ROOT}/proc log "installing grub on $DST..."
mount -o bind /dev ${GRUB_ROOT}/dev DSTMNT="/mnt/$DSTROOTLABEL"
mount -o bind /sys "$DSTMNT/sys"
mount -o bind /proc "$DSTMNT/proc"
mount -o bind /dev "$DSTMNT/dev"
chroot ${GRUB_ROOT} update-grub chroot "$DSTMNT" update-grub
chroot ${GRUB_ROOT} grub-install ${GRUB_DEV} chroot "$DSTMNT" grub-install "$DST"
# restart stopped process (db, etc...)
systemctl start mysql
exit 0
###############declare -a DSTLABELS_CHECK=(${SRCLABELS[@]/%?/$DSTCHAR})
# find corresponding LABELS on DEST disk
# declare -a LABELS=(${SRCLABELS[@]/%?/})
# for ((i=0; i<${#SRCLABELS[@]}; ++i)); do
# TMP="${LABELS[$i]}$DSTCHAR"
# echo -n "looking for partition 'LABEL=$TMP'... "
# if ! DSTFS=$(findfs LABEL="$TMP"); then
# echo "not found."
# exit 1
# fi
# echo "$DSTFS"
# DSTLABELS[$i]="$TMP"
# done
# #DSTLABELS=($(lsblk -lno LABEL "$DST"))
# # check all partitions types
# for ((i=0; i<${#SRCLABELS[@]}; ++1)); do
# check_block_device "source ${LABELS[$i]} partition" r "${SRCLABELS[$i]}"
# #check_block_device "destination ${LABELS[$i]} partition" w "${DSTLABELS[$i]}"
# done
# echo "DSTLABELS=${#DSTLABELS[@]} - ${DSTLABELS[*]}"
fi
exit 0 exit 0