#!/bin/sh
#
# $Header: https://svn.unixadm.org/repos/tools/qemu-backup.sh 1117 2015-01-25 16:03:49Z phil $
#

export PATH="${PATH}:/sbin:/usr/sbin"

pki=/home/phil/pki
[ -d "${pki}" ] || exit 1

if [ -z "$2" ]; then
	echo "usage: $0 <server> <imagefile.qcow2>"
	exit 1
fi

func=${0##*/}
host=$1
img=$2

if [ ! -e ${img} ]; then
	echo "imagefile ${img} does not exist!"
	exit 2
fi

rmmod nbd
modprobe nbd nbds_max=8 max_part=8

nbd=-1
for n in {0..7}; do
	nbd-client -c /dev/nbd${n}
	if [ $? -eq 1 ]; then
		nbd=$n
		break
	fi
done

if [ ${nbd} -lt 0 ]; then
	echo "no (free) nbd device found, exiting"
	exit 1
fi

echo "using nbd${nbd}"
tmp=$(mktemp -d)
mnt=${tmp}/mnt
mkdir -p ${tmp}/mnt
probe_dev="/dev/nbd${nbd}"
luks_dev=""
vg=""
mounts=""

qemu-nbd -c /dev/nbd${nbd} ${img}
sleep 1

p=1
while true; do
	[ -e /dev/nbd${nbd}p${p} ] || break
	tuuid=$(blkid -s UUID /dev/nbd${nbd}p${p} | cut -d\" -f2)
	if [ -n "${tuuid}" ]; then
		echo "found uuid $tuuid for /dev/nbd${nbd}p${p}"
		probe_dev="${probe_dev} /dev/nbd${nbd}p${p}"
	fi
	btype=$(blkid -s TYPE /dev/nbd${nbd}p${p} | cut -d\" -f2)
	if [ "${btype}" == "crypto_LUKS" ]; then
		echo "found luks device"
		if [ -r ${pki}/UUID=${tuuid} ]; then
			echo "found key for uuid ${tuuid}, opening"
			cryptsetup --key-file ${pki}/UUID=${tuuid} luksOpen \
				/dev/nbd${nbd}p${p} luks-${host} && \
			luks_dev="${luks_dev} luks-${host}"
			probe_dev="${probe_dev} /dev/mapper/luks-${host}"
		fi
	fi
	let p++
done

if [ $p -eq 1 ]; then
	echo "no partitions found, exiting"
	nbd-client -d /dev/nbd${nbd}
	rm -rf --one-file-system ${tmp}
	exit 13
fi

for p in {1..4}; do
	[ -e /dev/nbd${nbd}p${p} ] || continue
	mount /dev/nbd${nbd}p${p} ${mnt} >& /dev/null || continue
	if [ -e ${mnt}/grub/grub.conf ]; then
		echo "found /boot"
		root=$(perl -ne 'if (/root=(.+?) /) {print $1; last}' ${mnt}/grub/grub.conf)
		echo "grub says root is at ${root}"
		umount ${mnt}
		break
	elif [ -d ${mnt}/boot/grub ]; then
		root=/dev/nbd${nbd}p${p}
		echo "root found at ${root}"
		umount ${mnt}
		break
	fi
	umount ${mnt}
done

if [ -z "${root}" ]; then
	echo "root not found, exiting"
	nbd-client -d /dev/nbd${nbd}
	rm -rf --one-file-system ${tmp}
	exit 12
fi

pvscan --cache /dev/nbd${nbd}p*
for pd in ${probe_dev}; do
	tvg=$(pvdisplay -c ${pd} 2> /dev/null | cut -d: -f2)
	if [ -n "${tvg}" ]; then
		echo "found vg ${tvg}, activating"
		vgchange -a y ${tvg}
		vg="${vg} ${tvg}"
	fi
done

if [ ! -e "${root}" ]; then
	echo "root device ${root} does not exist. exiting."
	nbd-client -d /dev/nbd${nbd}
	rm -rf --one-file-system ${tmp}
	exit 12
fi

fsck -a -f ${root}
mount ${root} ${mnt}
if [ ! -r "${mnt}/etc/fstab" ]; then
	echo "fstab not readable. exiting."
	umount ${mnt}
	nbd-client -d /dev/nbd${nbd}
	rm -rf --one-file-system ${tmp}
	exit 12
fi
perl -ne 'next unless /^([^#]+?)\s+(\/[^\s]+?)\s+(?:ext[234]|btrfs|xfs|reiser.*?)\s/; printf "$1 $2\n"' ${mnt}/etc/fstab | while read dev mp; do
	fsck -a -f ${dev}
	mount ${dev} ${mnt}${mp}
done

echo "done, system is mounted at ${mnt}, disk is /dev/nbd${nbd}"

if [ "${func}" == "qemu-backup.sh" ]; then
	ping -c 2 -w 2 -q ${host} >& /dev/null
	if [ $? -ne 0 ]; then
		echo "host ${host} unreachable, not rsyncing"
		read
	else
		eval `ssh-agent -s`
		ssh-add 2>&1
		rsync ${3} -azvplHAXP --delete \
			--numeric-ids --inplace -e 'ssh -q' \
			--exclude=/proc/* --exclude=/sys/* --exclude=/selinux/* --exclude=/dev/* \
			--exclude=/var/named/chroot/proc/* --exclude=/tmp/* --exclude=/var/tmp/* \
			--exclude=/var/cache/yum/* --exclude=/var/cache/man/* --exclude=/luks/* \
			--exclude=/var/lib/imap/shm --exclude=/var/run/**.pid \
			--exclude=/multimedia_*/* --exclude=/srv/share/* --exclude=/home/phil/Downloads/* \
			${host}:/ ${mnt}
		sync

		kill $SSH_AGENT_PID
	fi
else
	echo "press play on tape."
	read
fi

mount | grep "${mnt}/" | awk '{print $3}' | while read m; do
	umount -v ${m}
done
umount -v ${mnt}
sync
for v in ${vg}; do
	vgchange -a n ${v}
	if [ $? -ne 0 ]; then
		rm -rf --one-file-system ${tmp}
		exit 255
	fi
done
sleep 1
for l in ${luks_dev}; do
	cryptsetup luksClose ${l}
	if [ $? -ne 0 ]; then
		rm -rf --one-file-system ${tmp}
		exit 255
	fi
done
sleep 1
nbd-client -d /dev/nbd${nbd}
rm -rf --one-file-system ${tmp}
