diff --git a/bash/dup-live-disk.sh b/bash/dup-live-disk.sh index 2f2be49..899c395 100755 --- a/bash/dup-live-disk.sh +++ b/bash/dup-live-disk.sh @@ -20,7 +20,7 @@ # # DESCRIPTION # 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. # 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 @@ -31,8 +31,17 @@ # must be 'root2', 'export2, and 'swap2'. # # OPTIONS -# -d, -n, --dry-run, --no -# Dry-run: nothing will be written to disk. +# -a, --autofs=DIR +# 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 # Install grub on destination disk. @@ -52,10 +61,6 @@ # Mandatory if SRC is provided, forbidden otherwise. # 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 # Copy sda to sdb, root partition is partition (sda1/sdb1) # $ 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. Options: - -d, -n, --dry-run, --no dry-run: nothing will be written to disk - -g, --grub install grub on destination disk - -h, --help this help - -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 - mandatory if and only if SRC is provided - -y, --yes DANGER ! perform all actions without user - confirmation + -a, --autofs=DIR autofs "LABEL-based" directory. Default is '/mnt'. + -c, --copy=ACTION do partitions copies ('yes'), do not copy then ('no') + or ask for each of them ('ask'). Default is 'no'. + -d, --dry-run dry-run: nothing will be written to disk + -g, --grub install grub on destination disk + -h, --help this help + -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 + mandatory if and only if SRC is provided SRC and DST have strong constraints on partitions schemes and naming. Type '$CMD --man" for more details" @@ -112,19 +118,19 @@ _EOF # mariadb start/stop function mariadb_maybe_stop { if [[ $MARIADB == yes ]] && systemctl is-active --quiet mysql; then - log -n "stopping mariadb/mysql... " - systemctl stop mariadb + #log -n "stopping mariadb/mysql... " + echorun systemctl stop mariadb # bug if script stops here MARIADBSTOPPED=yes - log "done." + #log "done." fi } function mariadb_maybe_start { if [[ $MARIADB == yes && $MARIADBSTOPPED == yes ]]; then - log -n "restarting mariadb/mysql... " - systemctl start mariadb + #log -n "restarting mariadb/mysql... " + echorun systemctl start mariadb MARIADBSTOPPED=no - log "done." + #log "done." fi } @@ -155,9 +161,12 @@ function log { # prints out and run a command. function echorun { - log "%s" "$@" - "$@" - return $? + if [[ "$DRYRUN" == 'yes' ]]; then + log "%s " "dry-run: " "$@" + else + log "%s " "$@" + "$@" + fi } function error_handler { @@ -168,15 +177,19 @@ function error_handler { trap 'error_handler $LINENO $?' ERR SIGHUP SIGINT SIGTERM function exit_handler { + local mnt + log "exit handler (at line $1)" mariadb_maybe_start - if [[ -v DSTMNT ]]; then - umount "$DSTMNT/dev" - umount "$DSTMNT/proc" - umount "$DSTMNT/sys" + if [[ -n "$DSTMNT" ]] && mountpoint -q "$DSTMNT"; then + for mnt in "$DSTMNT"/{dev,proc,sys}; do + if mountpoint -q "$mnt"; then + echorun umount "$mnt" + fi + done fi - } + trap 'exit_handler $LINENO' EXIT function check_block_device { @@ -237,14 +250,16 @@ SRC="" DST="" SRCROOT="" ROOTPARTNUM="" -DOIT=manual -MARIADB=no -MARIADBSTOPPED=no -GRUBINSTALL=no + +DRYRUN=no # dry-run +GRUB=no # install grub +COPY=no # do FS copies +MARIADB=no # stop/start mysql/mariadb +MARIADBSTOPPED=no # mysql stopped ? # short and long options -SOPTS="dnghmr:y" -LOPTS="dry-run,no,grub,help,man,mariadb,root:,yes" +SOPTS="c:dghmr:" +LOPTS="copy:,dry-run,grub,help,man,mariadb,root:" if ! TMP=$(getopt -o "$SOPTS" -l "$LOPTS" -n "$CMD" -- "$@"); then log "Use '$CMD --help' or '$CMD --man' for help." @@ -256,14 +271,22 @@ unset TMP while true; do case "$1" in - '-d'|'-n'|'--dry-run'|'--no') - DOIT=no + '-c'|'--copy') + case "$2" in + "no") COPY=no;; + "yes") COPY=yes;; + "ask") COPY=ask;; + *) log "invalid '$2' --copy flag" + usage + exit 1 + esac shift - continue + ;; + '-d'|'--dry-run') + DRYRUN=yes ;; '-g'|'--grub') - GRUBINSTALL=yes - shift + GRUB=yes ;; '-h'|'--help') usage @@ -275,7 +298,6 @@ while true; do ;; '--mariadb') MARIADB=yes - shift ;; '-r'|'--root') ROOTPARTNUM="$2" @@ -283,13 +305,7 @@ while true; do log "$CMD: $ROOTPARTNUM must be a partition number." exit 1 fi - shift 2 - continue - ;; - '-y'|'--yes') - DOIT=yes shift - continue ;; '--') shift @@ -301,9 +317,9 @@ while true; do exit 1 ;; esac + shift done - case "$#" in 1) if [[ -n "$ROOTPARTNUM" ]]; then @@ -355,7 +371,7 @@ declare -a LABELS=(${SRCLABELS[@]%?}) #log "LABELS=${#LABELS[@]} - ${LABELS[*]}" -declare -a SRCDEVS SRCFS SRCDOIT +declare -a SRCDEVS SRCFS SRC_VALID_FS # ... and corresponding partition device and fstype for ((i=0; i<${#LABELS[@]}; ++i)); do TMP="${LABELS[$i]}$SRCCHAR" @@ -365,8 +381,8 @@ for ((i=0; i<${#LABELS[@]}; ++i)); do log "found LABEL=$TMP DEV=$TMPDEV FSTYPE=$TMPFS" SRCDEVS[$i]="$TMPDEV" SRCFS[$i]="$TMPFS" - SRCDOIT[$i]=n - in_array "$TMPFS" VALIDFS && SRCDOIT[$i]=y + SRC_VALID_FS[$i]=n + in_array "$TMPFS" VALIDFS && SRC_VALID_FS[$i]=y unset TMP TMPDEV TMPFS done @@ -386,9 +402,8 @@ fi # log "ROOTLABEL=$ROOTLABEL" # log "SRCROOTLABEL=%s DSTROOTLABEL=%s" "$SRCROOTLABEL" "$DSTROOTLABEL" # 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 for ((i=0; i<${#LABELS[@]}; ++i)); do TMP="${LABELS[$i]}$DSTCHAR" @@ -408,8 +423,8 @@ for ((i=0; i<${#LABELS[@]}; ++i)); do DSTLABELS[$i]="$TMP" DSTDEVS[$i]="$TMPDEV" DSTFS[$i]="$TMPFS" - DSTDOIT[$i]=n - in_array "$TMPFS" VALIDFS && DSTDOIT[$i]=y + DST_VALID_FS[$i]=n + in_array "$TMPFS" VALIDFS && DST_VALID_FS[$i]=y unset TMP TMPDEV TMPFS done @@ -417,56 +432,47 @@ for ((i=0; i<${#LABELS[@]}; ++i)); do log -n "%s %s " "${SRCDEVS[$i]}" "${DSTDEVS[$i]}" log -n "%s %s " "${SRCLABELS[$i]}" "${DSTLABELS[$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 "*" 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" FILTER=--filter="dir-merge .rsync-disk-copy" # copy loop 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]}" continue fi SRCPART=/mnt/${SRCLABELS[$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" - skip=y - case "$DOIT" in - yes) - skip=n - ;; - no) - log "skipping (dry run)." - ;; - manual) - yesno "proceed ? [y/n/q]" && skip=n - ;; - esac - if [[ "$skip" == n ]]; then - # shellcheck disable=SC2086 + copy="$COPY" + if [[ "$COPY" == 'ask' ]]; then + yesno "Copy $SRCPART to $DSTPART ? [y/n/q]" && copy=yes || copy=no + fi + if [[ "$copy" == yes ]]; then mariadb_maybe_stop + # shellcheck disable=SC2086 echorun rsync "$FILTER" ${RSYNCOPTS} "$SRCPART" "$DSTPART" fi - log "" + #log "" done # grub install -# mount virtual devices -if [[ $GRUBINSTALL == yes ]]; then +if [[ "$GRUB" == yes ]]; then log "installing grub on $DST..." DSTMNT="/mnt/$DSTROOTLABEL" - mount -o bind /sys "$DSTMNT/sys" - mount -o bind /proc "$DSTMNT/proc" - mount -o bind /dev "$DSTMNT/dev" - - chroot "$DSTMNT" update-grub - chroot "$DSTMNT" grub-install "$DST" + # mount virtual devices + echorun mount -o bind /sys "$DSTMNT/sys" + echorun mount -o bind /proc "$DSTMNT/proc" + echorun mount -o bind /dev "$DSTMNT/dev" + echorun chroot "$DSTMNT" update-grub + echorun chroot "$DSTMNT" grub-install "$DST" fi exit 0