#!/bin/bash

# backup configs
BackupDirList="/etc /usr.syno.etc /var /usr/syno/synoman/webman/3rdparty /usr.local /root.ssh /usr/syno/selfcheck/packages"
BackupSubDirList="/etc/postgresql/user.conf.d"
RemoveUPSFiles="/usr/syno/etc/ups.conf /usr/syno/etc/upsd.conf /usr/syno/etc/upsd.users /usr/syno/etc/upsmon.conf /usr/syno/etc/upssched.conf"
RemovePPPOEFiles="/etc/ppp/ip-up /etc/ppp/ip-down /etc/ppp/ip-function /etc/ppp/ipv6-up /etc/ppp/ipv6-down /etc/ppp/options"
RemoveCUPSFilters="/usr/local/cups/filter/bannertops /usr/local/cups/filter/commandtops /usr/local/cups/filter/gziptoany /usr/local/cups/filter/imagetops /usr/local/cups/filter/imagetoraster /usr/local/cups/filter/pdftops /usr/local/cups/filter/pstops /usr/local/cups/filter/rastertoepson /usr/local/cups/filter/rastertohp /usr/local/cups/filter/rastertolabel /usr/local/cups/filter/rastertopwg /usr/local/cups/filter/texttops /usr/local/cups/filter/hpgltops"
RemoveCUPSFiles="/usr/local/cups/mime.types /usr/local/cups/mime.convs /etc/cups/cupsd.conf /usr/local/cups/cupsd.conf /usr/local/cups/testprint ${RemoveCUPSFilters}"
RemoveHostapdFiles="/etc/hostapd/stainfo.sh /etc/hostapd/mac_filter/mfscript.sh /usr/syno/etc/rfkill.sh"
RemoveSSLFiles="/usr/syno/etc/ssl/mkcert.sh /usr/syno/etc/ssl/mkcgikey.sh"
RemoveUSBModemFiles="/usr/syno/etc/usbmodem/wcdma_list.json /usr/syno/etc/usbmodem/usb_modeswitch.d/*"
RemovePHPFiles="/etc/php/php.ini /etc/php/php-fpm.conf /etc/php/conf.d/opcache.ini"
RemoveSynoServiceConf="/usr/syno/etc/synoservice.d/global.setting /usr/syno/etc/synoservice.d/system.cfg"
RemoveFileList="/etc/ftpusers /etc/rc /etc/rc.network /usr/syno/etc/rc.atalk /usr/syno/etc/.htpasswd /usr/syno/etc/lpd/lpd.conf /usr/syno/etc/printcap ${RemoveUPSFiles} /etc/lvm/lvm.conf /usr/local/etc/rc.d/SynoEnablePersonalServices.sh /etc/rc.network_routing /usr/syno/etc/rc.tun /usr/syno/etc/afpd.conf /etc/pam.d/samba ${RemovePPPOEFiles} ${RemoveCUPSFiles} ${RemoveHostapdFiles} /usr/syno/etc/iptables_guest_net.sh /etc/ld.so.preload /etc/tc/default.cmd $RemoveSSLFiles /etc/logrotate.conf $RemoveUSBModemFiles $RemovePHPFiles $RemoveSynoServiceConf /usr/syno/etc/ssdp/dsm_desc.xml /usr/syno/etc/iptables_time_ctrl.sh /etc/profile /etc/inputrc /etc/dhclient/dhclient-script /etc/dhclient/ipv4/dhclient.conf /etc/dhclient/ipv6/dhclient.conf /usr/syno/etc/www/SSLProfile.json /etc/vimrc /usr/syno/etc/cacert.pem /usr/syno/etc/iptables_modules_list /usr/syno/etc/iptables_chain_list /usr/local/bin/python* /etc/sudoers /usr/syno/etc/openldap/ldap.conf /usr/syno/etc/autoupdate.notify /etc/mtab"
RemoveCUPSDir="/usr/local/cups/backend /usr/local/cups/mime"
RemoveDirList="/etc/pam.d /usr/syno/etc/vfs /var/run /var/state/ups /usr/syno/etc/ups /var/spool/postfix ${RemoveCUPSDir} /etc/fw_security/sysconf /etc/init /etc/logrotate.d /etc/syslog-ng /var/lib/dpkg /etc/httpd/conf /etc/postgresql /etc/nginx /etc/wide-dhcpv6 /etc/apparmor.d /usr/syno/etc/synoservice.d /var/dynlib /etc/iproute2/script /etc/ssl/certs /etc/dbus-1 /usr/syno/etc/dbus-1 /etc/avahi /usr/syno/etc/synovpnclient/scripts /var/lib/apparmor /usr/syno/etc/www/app.d /usr/syno/etc/rc.d /usr/syno/etc/bluetooth/ /usr/syno/etc/smallupdate_patch /etc/ImageMagick-6 /usr/syno/etc/logcollector /var/cache/texts"
# list of folders who will be preserved util bootup finished
UpdateBackupDirList="/usr/syno/etc/synoservice.d /var/run/ha /var/run/ha_log_message.sqlite /var/run/first_time_synced /usr/syno/etc/timebkp /var/run"

GenerateTmpMnt() {
	rand=`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1`
	echo /tmp/${rand}
}

# BackupConfig RootMnt DataMnt
BackupConfig() {
	if [ -z "$1" -o -z "$2" -o ! -d $1 -o ! -d $2 ]; then
		/bin/echo "Failed to backup config: Wrong Parameters"
		exit 1
	fi

	local BKPDIR="$2/.upd@te"
	local BKPSUBDIR="$2/.upd@te_sub"
	# backup configs whose parent directory will be removed
	for ConfigSubDir in ${BackupSubDirList}; do
		if [ ! -d "$1/${ConfigSubDir}" ]; then
			continue
		fi
		/bin/mkdir -p ${BKPSUBDIR}/${ConfigSubDir}
		/bin/echo n | /bin/cp -afrP $1/$ConfigSubDir/* ${BKPSUBDIR}/${ConfigSubDir}/ 2> /dev/null
		/bin/echo n | /bin/cp -afrP $1/$ConfigSubDir/.[^.]* ${BKPSUBDIR}/${ConfigSubDir}/ 2> /dev/null
	done
	# backup user configs before upgrading
	for ConfigDir in ${BackupDirList}; do
		if [ ! -d "$1/${ConfigDir}" ]; then
			continue
		fi
		TargetConfigDir=""
		case $ConfigDir in
			/root.ssh)
				TargetConfigDir="/root/.ssh"
				;;
			/usr.local)
				TargetConfigDir="/usr/local"
				;;
			/usr.syno.etc)
				TargetConfigDir="/usr/syno/etc"
				;;
			*)
				TargetConfigDir=$ConfigDir
				;;
		esac
		/bin/mkdir -p ${BKPDIR}/${TargetConfigDir}
		/bin/echo n | /bin/cp -afrP $1/$ConfigDir/* ${BKPDIR}/${TargetConfigDir}/ 2> /dev/null
		/bin/echo n | /bin/cp -afrP $1/$ConfigDir/.[^.]* ${BKPDIR}/${TargetConfigDir}/ 2> /dev/null
	done

	# remove need-to-upgrade files
	for RemovalFile in ${RemoveFileList}; do
		/bin/rm -f ${BKPDIR}/${RemovalFile}
	done

	# remove need-to-upgrade dir
	for RemovalDir in ${RemoveDirList}; do
		/bin/rm -rf ${BKPDIR}/${RemovalDir}
	done
}

# RestoreConfig RootMnt DataMnt IsSameDevice
RestoreConfig() {
	if [ -z "$1" -o -z "$2" -o -z "$3" ]; then
		/bin/echo "Failed to restore config: Wrong Parameters"
		return 1
	fi

	local BKPDIR="$2/.upd@te"
	local BKPSUBDIR="$2/.upd@te_sub"

	# copy backed-up config files
	if [ "$3" = "yes" ]; then
		/bin/cp -alfP ${BKPDIR}/* $1/
		/bin/cp -alfP ${BKPSUBDIR}/* $1/
	else
		if [ -f ${BKPDIR}/etc/passwd -a -h $1/etc/passwd ]; then
			/bin/rm -f $1/etc/passwd
		fi
		if [ -f ${BKPDIR}/etc/group -a -h $1/etc/group ]; then
			/bin/rm -f $1/etc/group
		fi
		/bin/cp -arfP ${BKPDIR}/* $1/
		/bin/cp -arfP ${BKPSUBDIR}/* $1/
	fi
	# remove backup config files
	/bin/rm -rf ${BKPDIR}
	/bin/rm -rf ${BKPSUBDIR}
}

# ShareToFullPath share_name
ShareToFullPath() {
	synoshare --get "$1" > /dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo ""
		exit 1
	fi
	path=`synoshare --get "$1" | grep Path | awk '{split($2,a,"["); print a[2]}' | awk '{split($0,a,"]"); print a[1]}'`
	echo "${path}"
}

# DDSMConfigGet DDSM_Confstore
DDSMConfigGet() {
	BackupConfig "$1" "/volume1/@tmp"
}

# VDSMGetLunUUID vdsm_name vdisk_array_index
VDSMGetLunUUID() {
	local guest_object_path=""

	for guest_path in `etcdctl ls /syno/live_cluster/guests/`; do
		vm_name=`etcdctl get ${guest_path}/object | jq -r ".name"`
		if [ "${vm_name}" = "$1" ]; then
			guest_object_path="${guest_path}/object"
			break
		fi
	done
	if [ -z "${guest_object_path}" ]; then
		echo ""
		exit 1
	fi
	vdisk_uuid=`etcdctl get ${guest_object_path} | jq -r ".vdisks[$2]"`
	vdisk_lun_uuid=`etcdctl get "/syno/live_cluster/vdisk/${vdisk_uuid}/object" | jq -r '.uuid'`
	echo ${vdisk_lun_uuid}
}

# VDSMConfigSet vdisk2_lun_uuid
VDSMConfigSet() {
	tmp_mnt=`GenerateTmpMnt`

	if [ ! -d "/volume1/@tmp/.upd@te" ]; then
		echo "Cannot find /volume1/@tmp/.upd@te"
		exit 1
	fi

	if [ ! -d "/volume1/@tmp/.upd@te_sub" ]; then
		echo "Cannot find /volume1/@tmp/.upd@te_sub"
		exit 1
	fi

	/bin/mkdir -p ${tmp_mnt}

	ret=`synoiscsiwebapi l lm $1`
	if [ $? != 0 ]; then
		echo "loop mount fail"
		rmdir ${tmp_mnt}
		exit 1
	fi
	dev=`echo ${ret} | awk '{print $4}'`
	echo ${dev} | grep scsi
	if [ $? -eq 0 ]; then
		mount ${dev}p1 ${tmp_mnt}
	else
		mount ${dev}1 ${tmp_mnt}
	fi
	if [ $? != 0 ]; then
		echo "mount fail"
		rmdir ${tmp_mnt}
		synoiscsiwebapi l lu $1
		exit 1
	fi
	RestoreConfig ${tmp_mnt} "/volume1/@tmp" "no"
	# we remove pkg upstart config, and let it rebuild.
	rm -f ${tmp_mnt}/usr/share/init/pkg*
	rm -rf /volume1/@tmp/.upd@te
	rm -rf /volume1/@tmp/.upd@te_sub

	umount ${tmp_mnt}
	rmdir ${tmp_mnt}
	synoiscsiwebapi l lu $1
}

# VDSMCpVolume vdisk3_lun_uuid ddsm_store_path
VDSMCpVolume() {
	tmp_mnt=`GenerateTmpMnt`

	if [ ! -d $2 ]; then
		echo "Datastore path error"
		exit 1
	fi

	/bin/mkdir -p ${tmp_mnt}

	ret=`synoiscsiwebapi l lm $1`
	if [ $? != 0 ]; then
		echo "loop mount fail"
		rmdir ${tmp_mnt}
		exit
	fi
	dev=`echo ${ret} | awk '{print $4}'`

	echo 0 > "/config/target/core/fileio_0/LUN_$1/attrib/emulate_sync_cache"

	echo ${dev}
	base_dev=`basename ${dev}`
	echo 1024 > "/sys/block/${base_dev}/device/timeout"
	echo ${dev} | grep scsi
	if [ $? -eq 0 ]; then
		mount ${dev}p1 -o rw,relatime,space_cache=v2,metadata_ratio=50,synoacl ${tmp_mnt}
	else
		mount ${dev}1 -o rw,relatime,space_cache=v2,metadata_ratio=50,synoacl ${tmp_mnt}
	fi
	if [ $? != 0 ]; then
		echo "mount fail"
		rmdir ${tmp_mnt}
		echo 1 > "/config/target/core/fileio_0/LUN_$1/attrib/emulate_sync_cache"
		synoiscsiwebapi l lu $1
		exit
	fi
	for file in "$2"/*; do
		echo "${file}"
		base_file=`basename "${file}"`
		if [ ! -d "${file}" ]; then
			cp -afP "${file}" ${tmp_mnt}
			continue
		fi
		c=`echo "${base_file}" | cut -c 1`
		case $c in
			@)
				cp -arfP "$2/${base_file}" ${tmp_mnt}
				;;
			*)
				/bin/mkdir -p "${tmp_mnt}/${base_file}"
				synoacltool -copy "$2/${base_file}" "${tmp_mnt}/${base_file}"
				cp -arfP "$2/${base_file}"/* "${tmp_mnt}/${base_file}"
				;;
		esac
	done

	umount ${tmp_mnt}

	rmdir ${tmp_mnt}
	echo 1 > "/config/target/core/fileio_0/LUN_$1/attrib/emulate_sync_cache"
	synoiscsiwebapi l lu $1
}

PrintHelp() {
	echo "vmm_ddsm2vdsm <ddsm_share_name> <vdsm_name>"
}

#main ddsm_share_name vdsm_name
main() {
	if [ $# -lt 2 ]; then
		PrintHelp
		exit 1
	fi
	ddsm_path=`ShareToFullPath "$1"`
	if [ -z "${ddsm_path}" ]; then
		echo "Bad share name $1"
		exit 1
	fi
	vdisk2_lun_uuid=`VDSMGetLunUUID "$2" 1`
	if [ -z "${vdisk2_lun_uuid}" ]; then
		echo "Guest $2 not found."
		exit 1
	fi
	vdisk3_lun_uuid=`VDSMGetLunUUID "$2" 2`
	if [ -z "${vdisk3_lun_uuid}" ]; then
		echo "Guest $2 not found."
		exit 1
	fi

	DDSMConfigGet "${ddsm_path}/@synology_dockerdsm_conf/Confstore"
	echo "[1/3] Success to get DDSM config"

	VDSMConfigSet $vdisk2_lun_uuid
	echo "[2/3] Success to set DDSM config to VDSM"

	VDSMCpVolume $vdisk3_lun_uuid "${ddsm_path}/Datastore"
	echo "[3/3] Success to copy DDSM volume to VDSM"

	echo "Success"
}

echo -e "Copyright (c) 2000-2019 Synology Inc. All rights reserved.\n"

if [ $# -lt 2 ]; then
	PrintHelp
	exit 1
fi

ddsm_share_name="$1"
vdsm_name="$2"

main "${ddsm_share_name}" "${vdsm_name}"
