diff options
author | Michael Tokarev <mjt@tls.msk.ru> | 2012-01-11 17:57:30 +0400 |
---|---|---|
committer | Michael Tokarev <mjt@tls.msk.ru> | 2012-01-11 17:57:40 +0400 |
commit | aa9f8538e3707cc0e35aacddfd682e43038101a0 (patch) | |
tree | 51de02560184ca28f87066370cd84022d59f5bc2 /debian/mdadd.sh | |
parent | 04145749363e0180e8014b37eb3dfe59450f9bd4 (diff) |
move mdadd.sh from topgit branch to debian/
Diffstat (limited to 'debian/mdadd.sh')
-rw-r--r-- | debian/mdadd.sh | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/debian/mdadd.sh b/debian/mdadd.sh new file mode 100644 index 00000000..fafb15c6 --- /dev/null +++ b/debian/mdadd.sh @@ -0,0 +1,375 @@ +#!/bin/sh + +MY_VERSION="1.52a" +# ---------------------------------------------------------------------------------------------------------------------- +# Linux MD (Soft)RAID Add Script - Add a (new) harddisk to another multi MD-array harddisk +# Last update: January 10, 2012 +# (C) Copyright 2005-2012 by Arno van Amersfoort +# Homepage : http://rocky.eld.leidenuniv.nl/ +# Email : a r n o v a AT r o c k y DOT e l d DOT l e i d e n u n i v DOT n l +# (note: you must remove all spaces and substitute the @ and the . at the proper locations!) +# ---------------------------------------------------------------------------------------------------------------------- +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# version 2 as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# ---------------------------------------------------------------------------------------------------------------------- + +EOL=' +' + +show_help() +{ + echo "Bad or missing parameter(s)" + echo "Usage: $(basename $0) [ options ] [ source_disk ] [ target_disk ]" + echo "Options:" + echo "--force = Even proceed if target device does not appear empty" + echo "--noptupdate = Do NOT update the partition table on the target device (EXPERT!)" + echo "--nombrupdate = Do NOT update the MBR boot-loader on the target device (EXPERT!)" +} + + +get_partitions() +{ + local DEVICE="$(echo "$1" |sed s,'^/dev/',, )" + + if [ -z "$DEVICE" ]; then + cat /proc/partitions |sed -e '1,2d' -e s,' /dev/',, + else + cat /proc/partitions |sed -e '1,2d' -e s,' /dev/',, |grep -E " ${DEVICE}p?[0-9]+$" + fi +} + +get_part_size() +{ + get_partitions |grep -E " ${1}$" |awk '{ print $3 }' +} + +check_binary() +{ + if ! which "$1" >/dev/null 2>&1; then + printf "\033[40m\033[1;31mERROR: Binary \"$1\" does not exist or is not executable!\033[0m\n" >&2 + printf "\033[40m\033[1;31m Please, make sure that it is (properly) installed!\033[0m\n" >&2 + exit 2 + fi +} + + +sanity_check() +{ + if [ "$(id -u)" != "0" ]; then + printf "\033[40m\033[1;31mERROR: Root check FAILED (you MUST be root to use this script)! Quitting...\n\033[0m" >&2 + exit 1 + fi + + check_binary mdadm + check_binary sfdisk + check_binary dd + check_binary awk + check_binary grep + check_binary sed + check_binary cat + + if [ -z "$SOURCE" ] || [ -z "$TARGET" ]; then + echo "ERROR: Bad or missing argument(s)" >&2 + show_help; + exit 4 + fi + + if ! echo "$SOURCE" |grep -q '^/dev/'; then + printf "\033[40m\033[1;31mERROR: Source device $SOURCE does not start with /dev/! Quitting...\n\033[0m" >&2 + exit 5 + fi + + if ! echo "$TARGET" |grep -q '^/dev/'; then + printf "\033[40m\033[1;31mERROR: Target device $TARGET does not start with /dev/! Quitting...\n\033[0m" >&2 + exit 5 + fi + + if echo "$SOURCE" |grep -q 'md[0-9]'; then + printf "\033[40m\033[1;31mERROR: The source device specified is an md-device! Quitting...\n\033[0m" >&2 + echo "A physical drive (part of the md-array(s)) is required as source device (eg. /dev/sda)!" >&2 + exit 5 + fi + + # We also want variables without /dev/ : + SOURCE_NODEV="$(echo "$SOURCE" |sed 's,^/dev/,,')" + TARGET_NODEV="$(echo "$TARGET" |sed 's,^/dev/,,')" + + if [ -z "$(get_partitions ${SOURCE_NODEV})" ]; then + printf "\033[40m\033[1;31mERROR: Source device $SOURCE does not contain any partitions!? Quitting...\n\033[0m" >&2 + exit 7 + fi + + if [ -n "$(get_partitions ${TARGET_NODEV})" ] && [ $FORCE -ne 1 ]; then + sfdisk -l "$TARGET" + printf "\033[40m\033[1;31mERROR: Target device $TARGET already contains partitions! Use --force to override. Quitting...\n\033[0m" >&2 + exit 8 + fi + + SOURCE_SIZE="$(get_part_size $SOURCE_NODEV)" + TARGET_SIZE="$(get_part_size $TARGET_NODEV)" + if [ $SOURCE_SIZE -gt $TARGET_SIZE ]; then + printf "\033[40m\033[1;31mWARNING: Target device $TARGET ($TARGET_SIZE blocks) is smaller than source device $SOURCE ($SOURCE_SIZE blocks)\nPress enter to continue or CTRL-C to abort...\n\033[0m" >&2 + read + fi + + echo "--> Saving mdadm detail scan to /tmp/mdadm-detail-scan..." + mdadm --detail --scan --verbose >|/tmp/mdadm-detail-scan + retval=$? + if [ $retval -ne 0 ]; then + printf "\033[40m\033[1;31mERROR: mdadm returned an error($retval) while determining detail information!\n\033[0m" >&2 + exit 9 + fi + + echo "--> Saving partition table of target device $TARGET to /tmp/partitions.target..." + sfdisk -d "$TARGET" >|"/tmp/partitions.target" 2>/dev/null + retval=$? + if [ $retval -ne 0 ]; then + echo "NOTE: sfdisk returned an error($retval) while reading the partition table on $TARGET" + fi + + echo "--> Saving partition table of source device $SOURCE to /tmp/partitions.source..." + sfdisk -d "$SOURCE" >|"/tmp/partitions.source" + retval=$? + if [ $retval -ne 0 ]; then + printf "\033[40m\033[1;31mERROR: sfdisk returned an error($retval) while reading the partition table on $SOURCE!\n\033[0m" >&2 + exit 11 + fi + + echo "--> Checking status of running MDs..." + MD_DEV="" + IFS=$EOL + for MDSTAT_LINE in `cat /proc/mdstat`; do + if echo "$MDSTAT_LINE" |grep -q '^md'; then + MD_DEV_LINE="$MDSTAT_LINE" + MD_DEV="$(echo "$MDSTAT_LINE" |awk '{ print $1 }')" + + IFS=$EOL + for part_nodev in `cat "/tmp/partitions.target" |grep '^/dev/' |grep -i -v 'Id= 0' |awk '{ print $1 }' |sed 's,^/dev/,,'`; do + if echo "$MD_DEV_LINE" |grep -E -q "[[:blank:]]$part_nodev\["; then + printf "\033[40m\033[1;31mERROR: Partition /dev/$part_nodev on target device is already in use by array /dev/$MD_DEV!\n\033[0m" >&2 + exit 12 + fi + done + fi + + if echo "$MDSTAT_LINE" |grep -E -q '[[:blank:]]blocks[[:blank:]]' && ! echo "$MDSTAT_LINE" |grep -q '_'; then + # This array is NOT degraded so now check whether we want to add devices to it: + + IFS=$EOL + for part_nodev in `cat "/tmp/partitions.source" |grep '^/dev/' |grep -i -v 'Id= 0' |awk '{ print $1 }' |sed 's,^/dev/,,'`; do + if echo "$MD_DEV_LINE" |grep -E -q "[[:blank:]]$part_nodev\["; then + printf "$MD_DEV_LINE\n$MDSTAT_LINE\n" + printf "\033[40m\033[1;31mWARNING: Array $MD_DEV is NOT degraded, target device ${TARGET}$(echo "$part_nodev" |sed "s,$SOURCE_NODEV,,") will become a hotspare!\nPress enter to continue or CTRL-C to abort...\n\033[0m" >&2 + read + fi + done + fi + done +} + + +# Wrapper for partprobe (call when performing a partition table update with eg. fdisk/sfdisk). +# $1 = Device to re-read +partprobe() +{ + local DEVICE="$1" + local result="" + + printf "(Re)reading partition table on $DEVICE" + + # Retry several times since some daemons can block the re-reread for a while (like dm/lvm or blkid) + for x in `seq 1 10`; do + printf "." + result=`sfdisk -R "$DEVICE" 2>&1` + + # Wait a bit for things to settle + sleep 1 + + if [ -z "$result" ]; then + break; + fi + done + + echo "" + + if [ -n "$result" ]; then + echo "$result" >&2 + return 1 + fi + return 0 +} + + +# Program entry point +echo "MDadd for SoftRAID-MDADM v$MY_VERSION" +echo "Written by Arno van Amersfoort" +echo "--------------------------------" + +# Set environment variables to default +FORCE=0 +NOPTUPDATE=0 +NOMBRUPDATE=0 +SOURCE="" +TARGET="" + +# Check arguments +unset IFS +for arg in $*; do + ARGNAME="$(echo "$arg" |cut -d= -f1)" + ARGVAL="$(echo "$arg" |cut -d= -f2)" + + if ! echo "$ARGNAME" |grep -q '^-'; then + if [ -z "$SOURCE" ]; then + SOURCE="$ARGVAL" + else + if [ -z "$TARGET" ]; then + TARGET="$ARGVAL" + else + show_help; + exit 3 + fi + fi + else + case "$ARGNAME" in + --force|-force|-f) FORCE=1;; + --noptupdate|-noptupdate|--noptu|-noptu) NOPTUPDATE=1;; + --nombrupdate|-nombrupdate|--nombru|nombru) NOMBRUPDATE=1;; + --help) show_help; + exit 0;; + *) echo "ERROR: Bad argument: $ARGNAME"; + show_help; + exit 3;; + esac + fi +done + +# Make sure everything is sane: +sanity_check; + +# Disable all swaps on target disk +echo "--> Disabling any swap partitions on target device $TARGET" +IFS=$EOL +for SWAP in `grep -E "^${TARGET}p?[0-9]+" /proc/swaps |awk '{ print $1 }'`; do + swapoff $SWAP >/dev/null 2>&1 +done + +# Update track0 on target disk +if [ $NOMBRUPDATE -ne 1 ]; then + echo "--> Copying track0(containing MBR) from $SOURCE to $TARGET..." + dd if="$SOURCE" of="$TARGET" bs=32768 count=1 + retval=$? + if [ $retval -ne 0 ]; then + printf "\033[40m\033[1;31mERROR: dd returned an error($retval) while copying track0!\n\033[0m" >&2 + exit 9 + fi +fi + +PT_FILE="/tmp/partitions.source" +if [ $NOPTUPDATE -eq 1 ]; then + PT_FILE="/tmp/partitions.target" +fi + +echo "--> Restoring partition table from $PT_FILE to $TARGET..." +sfdisk --no-reread --force "$TARGET" < "$PT_FILE" +retval=$? +if [ $retval -ne 0 ]; then + printf "\033[40m\033[1;31mERROR: sfdisk returned an error($retval) while writing the partition table!\n\033[0m" >&2 + exit 9 +fi + +echo "" + +if [ $NOPTUPDATE -ne 1 ]; then + # Re-read partition table + partprobe "$TARGET" + retval=$? + if [ $retval -ne 0 ]; then + printf "\033[40m\033[1;31mERROR: (Re)reading the partition table failed($retval)!\n\033[0m" >&2 + exit 9 + fi +fi + +# Copy/build all md devices that exist on the source drive: +BOOT=0 +NO_ADD=1 +IFS=$EOL +for LINE in `cat /tmp/mdadm-detail-scan`; do + if echo "$LINE" |grep -E -q '^ARRAY[[:blank:]]'; then + MD_DEV=$(echo "$LINE" |awk '{ print $2 }') + fi + + if echo "$LINE" |grep -E -q "devices=.*${SOURCE}p?[0-9]+"; then + PARTITION_NR="" + IFS=',' + for item in `echo "$LINE" |sed -e "s:.*devices=::"`; do + if echo "$item" |grep -E -q -x "${SOURCE}p?[0-9]+"; then + PARTITION_NR=`echo "$item" |sed s:"$SOURCE"::` + break; + fi + done + + if [ -z "$PARTITION_NR" ]; then + printf "\033[40m\033[1;31mERROR: Unable to retrieve detail information for $SOURCE from $MD_DEV!\n\033[0m" >&2 + exit 11 + fi + + # Check whether we're a root or boot partition + if grep -E -q -e "^$MD_DEV[[:blank:]]*/boot[[:blank:]]" -e "$MD_DEV[[:blank:]]*/[[:blank:]]" /etc/fstab; then + BOOT=1 + fi + + NO_ADD=0 + echo "" + echo "--> Adding ${TARGET}${PARTITION_NR} to RAID array $MD_DEV:" + printf "\033[40m\033[1;31m" + mdadm --add "$MD_DEV" "${TARGET}${PARTITION_NR}" + retval=$? + if [ $retval -ne 0 ]; then + printf "\033[40m\033[1;31mERROR: mdadm returned an error($retval) while adding device!\n\033[0m" >&2 + exit 12 + fi + printf "\033[0m" + fi +done + +echo "" + +# Create swapspace on partitions with ID=82 +echo "--> Creating swapspace on target device (if any swap partitions exist)..." +IFS=$EOL +for SWAP_DEVICE in `sfdisk -d "$TARGET" 2>/dev/null |grep -i 'Id=82$' |awk '{ print $1 }'`; do + if ! mkswap "$SWAP_DEVICE"; then + printf "\033[40m\033[1;31mWARNING: mkswap failed for $SWAP_DEVICE\n\033[0m" >&2 + else + swapon "$SWAP_DEVICE" + fi + + if ! grep -E -q "^$SWAP_DEVICE[[:blank:]]*none[[:blank:]]*swap[[:blank:]]" /etc/fstab; then + printf "\033[40m\033[1;31mWARNING: /etc/fstab does NOT contain a (valid) swap entry for $SWAP_DEVICE\n\033[0m" >&2 + fi +done + +# Wait a bit for mdstat to settle +sleep 3 + +echo "--> Showing current /proc/mdstat (you may need to update your mdadm.conf (manually)..." +cat /proc/mdstat +echo "" + +if [ $NO_ADD -eq 1 ]; then + printf "\033[40m\033[1;31mWARNING: No mdadm --add actions were performed, please investigate!\n\033[0m" >&2 +fi + +if [ $BOOT -eq 1 ]; then + printf "\033[40m\033[1;31mNOTE: Boot and/or root partition detected.\n Please check your bootloader & active partitions!\n\033[0m" +fi |