#!/bin/sh
# sauvegarde d'un disque systeme sur un autre
# version 1.3 du 01/04/2004 par E Gerbier eric.gerbier@free.fr
# license : GPL
# environnement : 
# DEBUG : pour avoir des infos de debugage
# VERBOSE : pour voir ce qui est modifie
# utilise : rsync
PATH=$PATH:/sbin:/usr/bin:/usr/sbin
sortie_menage () {
	if [ -z "$DEBUG" ]
	then
		rm -rf $REP 2>/dev/null
	else
		echo "informations de debugage sur $REP"
	fi
	exit
}

###################################################################

creer_table_partitions() {
	echo -n "le disque est-il monte ? : "
	out=$(df -P | grep ${disque_dest})
	if [ -n "$out" ]
	then
		echo "demonter les partitions avant utilisation svp"
		sortie_menage
	else
		echo "ok (non monte)"
	fi

	echo -n "repartitionnement de  ${disque_dest} : "

	# il y a une bug avec la langue francaise (premiere ligne)
	awk '/^\/dev/'  $table_dest_attendue | sfdisk -uS --force ${disque_dest}

	# verification
	echo -n "verification des partitions : "
	table_cree=${REP}/table_cree
	sfdisk -uS -d ${disque_dest} > $table_cree
	diff -bw $table_dest_attendue $table_cree > /dev/null
	irep=$?
	if [ $irep -ne 0 ]
	then
		echo "KO"
		diff -bw $table_dest_attendue $table_cree
		sortie_menage
	else
		echo "ok"
	fi
}

###################################################################

format_partitions() {

	echo "on reformatte les partitions"

	# il faut sauter des lignes
	awk '/^\/dev/'  $table_dest_attendue | while read line
	do
		device=$(echo "$line" | cut -f1 -d" ")
		ext=$(echo "$line" | egrep " 83 |Id=83" )
		swap=$(echo "$line" | egrep " 82 |Id=82" )
		if [ -n "$ext" ]
		then
			# 3 cas possibles : ext2, ext3 et reiserfs
			device_local=$(echo "$device" | sed -e "s/${disque_dest_sed}/${disque_src_sed}/g")
			out_fstab=$(awk "\$1 == \"$device_local\" { print \$3}" /etc/fstab)
			mount_point=$(awk "\$1 == \"$device_local\" { print \$2}" /etc/fstab)
			out_ext2=$(echo "$out_fstab" | grep ext2)
			out_ext3=$(echo "$out_fstab" | grep ext3)
			out_reiser=$(echo "$out_fstab" | grep reiserfs)
			if [ -n "$out_ext2" ]
			then
				echo "formattage $device ($mount_point) en ext2"
				mke2fs $device
			elif [ -n "$out_ext3" ]
			then
				echo "formattage $device ($mount_point) en ext3"
				mke2fs -j $device
			elif [ -n "$out_reiser" ]
			then
				echo "formattage $device ($mount_point) en reiserfs"
				mkreiserfs $device << EOF
y
EOF
			elif [ -n "$out_fstab" ]
			then
				echo "WARNING : $device_local non reconnu dans fstab : $out_fstab"
			fi
		elif [ -n "$swap" ]
		then
			echo "formattage $device en swap"
			mkswap $device
		fi
	done
}

###################################################################

verifications () {
# il faut donner 2 ou 3 arguments : 
# - disque de depart
# - disque d'arrivee
# - optionnel pour forcer la copie totale

if [ -n "$DEBUG" ]
then
	verbose="-v"
fi

if [ -n "$VERBOSE" ]
then
	verbose="-v"
fi

if [ $# -eq 3 ]
then
	disque_src=$1
	disque_dest=$2
	FORCE=y
	verbose=""
elif [ $# -eq 2 ]
then
	disque_src=$1
	disque_dest=$2
else
	echo "syntaxe : $0 disque-source disque_dest [force]"
	exit
fi

clear

# il faut etre root pour le lancer
uid=$(id -u)
if [ $uid -ne 0 ]
then
	echo "il faut etre root"
	exit
fi

# test du PATH
out=$(echo "$PATH" | grep "/sbin")
if [ -z "$out" ]
then
	echo "verifier le PATH : il faut avoir /sbin"
	exit
fi


# verification que le disque source est bien le disque monte
out=$(df -P | awk '$6 == "/" { print $1}' | grep $disque_src)
if [ -z "$out" ]
then
	echo "le disque source ($disque_src) ne correspond pas au disque monte"
	exit
fi

# verification pas de label
out=$(grep "^LABEL=" /etc/fstab)
if [ -n "$out" ]
then
	echo "label non supportes : modifier le fichier /etc/fstab svp"
	exit
fi


#espace temporaire de travail
REP=/tmp/$(basename $0).$$
mkdir $REP

echo -n "verification de l'existence des disques ${disque_src} et  ${disque_dest} : "
table_src=${REP}/table_src
sfdisk -uS -d ${disque_src} > ${table_src} 2>/dev/null
if [ ! -s "$table_src" ]
then
	echo "disque  ${disque_src} inexistant"
	sortie_menage
fi
table_dest=${REP}/table_dest
sfdisk -uS -d ${disque_dest} > ${table_dest} 2>/dev/null
if [ ! -s "$table_dest" ]
then
	echo "disque  ${disque_dest} inexistant"
	sortie_menage
fi
echo "ok"

# le sed ne supporte pas les /, il faut les changer en \/
disque_src_sed=$(echo "${disque_src}" | sed -e 's/\//\\\//g')
disque_dest_sed=$(echo "${disque_dest}" | sed -e 's/\//\\\//g')

# on calcule la table attendue
table_dest_attendue=${REP}/table_dest_attendue
cat $table_src | sed -e "s/${disque_src_sed}/${disque_dest_sed}/g" > $table_dest_attendue
}

###################################################################################
# on attaque la copie des file systems du disque source
copie_donnees () {

#awk 'NR > 5' $table_dest_attendue | while read line
awk '/^\/dev/' $table_dest_attendue | while read line
do
	device_bis=$(echo "$line" | cut -f1 -d" ")

	# on replace les / par des _ pour le point de montage
	device_mont=$(echo "$device_bis" | sed 's/\//_/g')
	ext=$(echo "$line" | egrep "Id=83| 83 " )
	if [ -n "$ext" ]
	then
		# montage disque de copie
		if [ ! -d /mnt/${device_mont} ]
		then
			mkdir /mnt/${device_mont}
		fi
		# echo "montage de $device_bis sur /mnt/${device_mont}"
		# 3 cas possibles : ext2 et reiserfs
		device_local=$(echo "$device_bis" | sed -e "s/${disque_dest_sed}/${disque_src_sed}/g")
		#out_fstab=$(awk "\$1 == \"$device_local\" { print \$3}" /etc/fstab)
		out_fstab=$(df -T $device_local | awk "\$1 == \"$device_local\" { print \$2}")
		out_ext2=$(echo "$out_fstab" | grep ext2)
		out_ext3=$(echo "$out_fstab" | grep ext3)
		out_reiser=$(echo "$out_fstab" | grep reiserfs)
		if [ -n "$out_ext2" ]
		then
			e2fsck  -p $device_bis
			mount $device_bis /mnt/${device_mont}
		elif [ -n "$out_ext3" ]
		then
			e2fsck  -p $device_bis
			mount -t ext3 $device_bis /mnt/${device_mont}
		elif [ -n "$out_reiser" ]
		then
			reiserfsck -x  $device_bis << EOF
Yes
EOF
			mount -t reiserfs $device_bis /mnt/${device_mont}
		elif [ -n "$out_fstab" ]
		then
			echo "WARNING : type de $device_bis pas trouve dans fstab"
			continue
		else
			echo "INFO : $device_local pas dans /etc/fstab"
			continue
		fi
		irep=$?
		if [ $irep -ne 0 ]
		then
			echo "WARNING : probleme montage de $device_bis sur /mnt/${device_mont}"
			continue
		fi

		# point de montage local
		device_local=$(echo "$device_bis" | sed -e "s/${disque_dest_sed}/${disque_src_sed}/g")
		mont_local=$(awk "\$1 == \"$device_local\" { print \$2}" /etc/fstab)

		# copie
		if [ -n "$mont_local" ]
		then
			# on ne copie que les montage par defaut de fstab
			out=$(awk "\$1 == \"$device_local\" { print \$0}" /etc/fstab | grep defaults)
			if [ -z "$out" ]
			then
				echo "$mont_local n'est pas monte par defaut : pas de copie"
				continue
			fi

			if [ "$mont_local" = "/mnt" ]
			then
				echo "on ne copie pas /mnt"
#			elif [ "$mont_local" = "/home" ]
#			then
#				echo "on ne copie pas /home"
#			elif [ "$mont_local" = "/tmp" ]
#			then
#				echo "on ne copie pas /tmp"
			elif [ "$mont_local" = "/" ]
			then
				echo "copie de / sur /mnt/${device_mont}"
				# il faut prendre quelques precautions concernant /proc /tmp /dev
				# solution 1 : cpio
				# rem : j'utilise cpio et je copie donc tout car je n'ai pas trouve de config pour cp qui marche
				#find / -xdev -path /proc -prune -o -path /tmp -prune -o -path /home -prune -o -path /mnt -prune -o -print | cpio -pdmu ${verbose} /mnt/${device_mont}
				# par contre je ne garantis pas les scories distantes

				# solution 2 : rsync
				cd /
				time nice rsync -ax ${verbose} --delete --exclude "/proc/*" --exclude "/mnt/*" --exclude ".journal" . /mnt/${device_mont}
				cd -

				# copie de quelques fichiers speciaux qui contiennent les device
				sed -e "s/${disque_src_sed}/${disque_dest_sed}/g" /etc/fstab > /mnt/${device_mont}/etc/fstab


				# config lilo
#			sed -e "s/${disque_src_sed}/tototo/g" /etc/lilo.conf |sed -e "s/${disque_dest_sed}/${disque_src_sed}/g"| sed -e "s/tototo/${disque_dest_sed}/g" > /mnt/${device_mont}/etc/lilo.conf

				# partition /boot ?
				out=$(grep "/boot" /etc/fstab)
				if [ -n "$out" ]
				then
					chroot /mnt/${device_mont} mount /boot
				fi
				echo "boot sur le disque  ${disque_dest} de `hostname` " > /mnt/${device_mont}/boot/message.txt
# 			chroot /mnt/${device_mont} lilo -v
				if [ -n "$out" ]
				then
					chroot /mnt/${device_mont} umount /boot
				fi

				# /etc/mtab
				cp /dev/null /mnt/${device_mont}/etc/mtab

				#copie des points de montage des fs non copies
				mkdir -m 555 /mnt/${device_mont}/proc 2>/dev/null
				mkdir -m 1777 /mnt/${device_mont}/tmp 2>/dev/null
				mkdir -m 755 /mnt/${device_mont}/home 2>/dev/null
				mkdir -m 755 /mnt/${device_mont}/mnt 2>/dev/null

			else
				echo "copie de $mont_local sur /mnt/${device_mont}"
				# solution "cp"
				#cd $mont_local
				#nice cp -ax ${cp_update} . /mnt/${device_mont}
				#cd -

				# solution "rsync
				cd $mont_local
				time nice rsync -ax ${verbose} --exclude ".journal" --delete . /mnt/${device_mont}
				cd -

				# solution "cpio"
				#find $mont_local -xdev -print | cpio -pdmu ${verbose} /mnt/${device_mont}

			fi
		else
			echo "$device_local pas dans /etc/fstab"
		fi

		# comparaison des device
		df -P| egrep "$device_local |$device_bis "

		#demontage
		umount /mnt/${device_mont}
		rmdir /mnt/${device_mont}
	fi
done
}


##############################################################################################

#set -x

verifications $*

echo -n "comparaison des partitions : "

diff -bw $table_dest_attendue ${table_dest} > /dev/null
irep=$?
if [ $irep -ne 0 ]
then
	echo "les partitions sont differentes :"
	sdiff $table_dest_attendue ${table_dest} 

	creer_table_partitions
	FORCE=y
	verbose=""
else
	echo "ok (identiques)"
fi

# petit probleme avec sfdisk sur les partitions raid !!!
# on utilise donc par la suite une sortie fdisk
fdisk -l $disque_dest >  $table_dest_attendue

if [ -n "$FORCE" ]
then
	format_partitions
fi

copie_donnees

sortie_menage
