#!/bin/bash

HELPER=$0-helper
WORKDIR=`mktemp -d /tmp/csm-converter.$(date +"%Y-%m-%dT%H:%M").XXXXXX`
SECTOR_COUNT=1024

if [ `id -u` -ne 0 ]; then
  echo "ERROR: You have to run this as root."
  exit 1
fi

pushd $WORKDIR > /dev/null
export slaves=
export scan_devs=
export convert_devs=
export forced=0
export do_scan=0
export do_test=0
export all_opts=

if [ $# -eq 0 ]; then
	echo Usage: $0 dev1 dev2 dev3 ...
	exit 0
fi

for opt in $*; do
	if [ $opt == "--force" ]; then
		export forced=1
		continue
	elif [ $opt == "--scan" ]; then
		export do_scan=1
		continue
	elif [ $opt == "--test" ]; then
		export do_test=1
		continue
	fi
	all_opts="$all_opts $opt"
done

if [ "$1" == "--help" ]; then
	echo "Usage: $0 [--force] [--scan] [---test] dev1 dev2 dev3 ..."
	exit 0
fi

check_dev() {
	local opt="$1"
	xxd -l 8 $opt | egrep -q "CSM PART"
	if [ $? -ne 0 ]; then
		echo "$opt is not a CSM Container."
		continue
	fi

	last_sector=`blockdev --getsz $opt`
	last_sector=`expr $last_sector - 1`
	dd if=$opt of=last_sector skip=$last_sector ibs=512 count=1 > /dev/null 2>&1
	xxd -l 8 last_sector | egrep -q "CSM PART"
	rc=$?
	rm last_sector
	if [ $rc -ne 0 ]; then
		echo "The CSM metadata on $opt is not consistent."
		return 1
	fi
	$HELPER $opt 2>&1 > /dev/null
	if [ $? -ne 0 ]; then
		echo "LVM2 metadata cannot be found inside $opt"
		return 1
	fi
	echo "$opt is a valid CSM container."
	return 0
}

if [ $do_scan -eq 1 ]; then
	devs=`find /dev -maxdepth 3 -type b | \
		 egrep -v "loop" | \
		 egrep -v "cciss" | \
		 egrep -v "md" | \
		 egrep -v "fd" | \
		 egrep -v "evms" | \
		 egrep -v "ram" | \
		 egrep -v "drbd" | \
		 egrep -v "hd[a-z]" | \
		 egrep -v "mapper\/" | \
		 egrep -v "sd[a-z][0-9]+" 2>/dev/null`

	for dev in $devs; do
		name=`echo $dev | awk -F\/ '{print $NF}'`
		echo $dev | egrep -q "dm-"
		if [ $? -eq 0 ]; then
			for slave in `ls /sys/block/${name}/slaves/ 2>/dev/null`; do
				echo $slaves | egrep -q "\<$slave\>"
				if [ $? -ne 0 ]; then
					echo $slave | egrep -q ".*[0-9]+$"
					if [ $? -ne 0 ]; then
						export slaves="$slaves $slave"
					fi
				fi
			done
		fi
	done

	for dev in $devs; do
		echo $slaves | egrep -q "\<$dev\>"
		if [ $? -ne 0 ]; then
			export scan_devs="$scan_devs $dev"
		fi
	done
else
	export scan_devs="$all_opts"
fi

for dev in $scan_devs; do
	if check_dev $dev ; then
		if [ $do_test -eq 1 ]; then
			continue
		fi
		if [ $forced -eq 0 ]; then
			echo $dev 'is a CSM container. Do you want to convert it ? [y/N]'
			read sel
			if [[ x$sel =~ x[yY].* ]]; then
				export convert_devs="$convert_devs $dev"
				continue
			fi
		else
			export convert_devs="$convert_devs $dev"
			continue
		fi
	fi
done

if [ $do_test -eq 1 ]; then
	exit 0
fi

echo "Backup copies of the meta-data are saved to $WORKDIR"

for dev in $convert_devs; do
	echo "Beginning conversion of $dev"
	name=`echo $dev | awk -F/ '{print $NF}'`
	dd if=$dev of=${name}_first_sectors.img bs=512 count=$SECTOR_COUNT >/dev/null 2>&1 
	dd if=$dev of=${name}_last_sector.img bs=512 count=1 >/dev/null 2>&1 
	if [ $? -ne 0 ]; then
		echo "ERROR: Failed to create meta-data backup - abort!"
		exit 1
	fi

	$HELPER $dev >/dev/null 2>&1 
	if [ $? -ne 0 ]; then
		echo "ERROR: $HELPER failed to extract metadata from $dev."
		exit 1
	fi

	for pe_start_orig in `egrep -n pe_start metadata | awk '{printf "%s:%s\n",$1,$3}'`; do
		line=`echo $pe_start_orig | awk -F: '{printf $1}'`
		pe_start=`echo $pe_start_orig | awk -F: '{printf $3}'`
		pe_start_new=`expr $pe_start \+ 1`
		sed -e "$line s/pe_start = $pe_start/pe_start = $pe_start_new/" metadata > metadata.tmp
		mv metadata.tmp metadata
	done

	VGNAME="`head -n 1 metadata  | awk '{print $1}'`"
	if [ -z "$VGNAME" ]; then
		echo "ERROR: No valid vgname found on $dev"
		exit 1
	fi

	mkdir -p $VGNAME
	for i in `ls $VGNAME` ; do
		cmp ${VGNAME}/${i} metadata
		if [ $? -ne 0 ]; then
			echo "ERROR: LVM2 metadata on $i does not agree with $dev"
			exit 1
		fi
	done
	cp metadata $VGNAME/`cat pvuuid`
	last_sector=`blockdev --getsz $dev`
	last_sector=`expr $last_sector - 1`

	echo "Converting $dev to standard physical volume."
	dd if=/dev/zero of=$dev bs=512 count=4 > /dev/null 2>&1
	dd if=/dev/zero of=$dev seek=$last_sector bs=512 count=1 > /dev/null 2>&1
	pvcreate --uuid `cat pvuuid` --restorefile metadata $dev -ff

	pv_required=`egrep "pv[0-9]* {" metadata | wc -l`
	pv_has=`ls $VGNAME | wc -l`

	if [ $pv_required -eq $pv_has ]; then
		echo "Restoring vgcfg as all of required physical volumes are recovered."
		vgcfgrestore -f metadata $VGNAME

		echo "Trying to activte $VGNAME"
		vgchange -aly $VGNAME
		rc=$?
		if [ $rc -eq 0 ]; then
			echo "$VGNAME activated"
			for lv in `lvs --noheadings $VGNAME | awk '{print $1}'`; do
				export `vol_id /dev/${VGNAME}/${lv}`
				if [ fsck.${ID_FS_TYPE} != fsck. ]; then
					fsck.${ID_FS_TYPE} -n /dev/${VGNAME}/${lv}
					if [ $? -ne 0 ]; then
						echo "WARNING: fsck failed on /dev/${VGNAME}/${lv}"
						echo "WARNING: Please check it manually."
						continue
					fi
				fi
			done
			vgchange -aln $VGNAME
			vgchange -cy $VGNAME
		fi
	fi

	echo "Conversion $dev is done."
	mv pvuuid ${name}_pvuuid
	mv metadata ${name}_metadata

done

echo "Backup copies of the meta-data were saved to $WORKDIR"

echo Done.
popd > /dev/null
