#!/bin/bash

set -e
shopt -s extglob

SET_RANDOM_ADMIN_PW=1

run() {

if [ "x$EUID" != x0 ]
then
	echo "Please run as root user"
	exit
fi

echo "Deploying Infscape UrBackup Appliance on this instance."

if ! command -v blockdev > /dev/null 2>&1
then
	echo "blockdev command missing. Please install."
	exit 1
fi

ROOT_DEV=$(df -P / | tail -n 1 | awk '/.*/ { print $1 }' | sed "s@/dev/@@")
if [ -e /sys/class/block/$ROOT_DEV/partition ]
then
        ROOT_DEV=$(basename "$(readlink -f "/sys/class/block/$ROOT_DEV/..")")
fi

INST_INFO=$(uname -a)
HOSTNAME_INFO=$(hostname -f)
echo "Running on $INST_INFO hostname $HOSTNAME_INFO"
uptime || true
echo "Proceeding will overwrite (DELETE!) all data on the root device ($ROOT_DEV)... Proceed? [y/N]"
read yn
if [ "x$yn" != xy ] && [ "x$yn" != "Y" ]
then
	exit 5
fi

if [ "x$SET_RANDOM_ADMIN_PW" = "x1" ]
then
	LOGIN_PWD=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
	echo "Generated login password. Please use this password during setup after the appliance is deployed: $LOGIN_PWD"
fi

echo "Cleaning..."
export DEBIAN_FRONTEND=noninteractive
apt-get remove libllvm7 -y > /dev/null 2>&1 || true
apt-get remove libpython3.7-dev -y > /dev/null 2>&1 || true
apt-get remove libopenblas-dev -y > /dev/null 2>&1 || true
apt-get remove guile-2.2-libs -y > /dev/null 2>&1 || true
apt-get remove libopenblas-base -y > /dev/null 2>&1 || true
apt-get remove gcc-8 -y > /dev/null 2>&1 || true
apt-get remove g++-8 -y > /dev/null 2>&1 || true
apt-get remove cpp-8 -y > /dev/null 2>&1 || true
apt-get remove libperl5.28 -y > /dev/null 2>&1 || true
apt-get remove dpkg-dev -y > /dev/null 2>&1 || true
apt-get remove perl-modules-5.28 -y > /dev/null 2>&1 || true
apt-get remove cmake -y > /dev/null 2>&1 || true
apt-get remove iso-codes -y > /dev/null 2>&1 || true
apt-get remove vim-runtime -y > /dev/null 2>&1 || true
apt-get remove libicu63 -y > /dev/null 2>&1 || true
apt-get autoremove -y > /dev/null 2>&1 || true

echo "Setting up in-memory base system..."

modprobe loop > /dev/null 2>&1 || true
modprobe btrfs > /dev/null 2>&1 || true
swapoff -a || true
mkdir -p /tmproot
TMPFS_SIZE=$((3500*1024*1024))
if ! command -v zramctl > /dev/null 2>&1 || ! modprobe zram > /dev/null 2>&1 || ! command -v mkfs.ext4 > /dev/null 2>&1
then
	echo "Using tmpfs..."
	mount -t tmpfs none /tmproot -o size=$TMPFS_SIZE
else
	echo "Using zram..."
	ZRAMDEV=$(zramctl -f)
	zramctl -b -s $((3500*1024*1024)) $ZRAMDEV
	echo "Formatting zram device..."
	mkfs.ext4 $ZRAMDEV > /dev/null
	mount $ZRAMDEV /tmproot
fi
mkdir /tmproot/{proc,sys,dev,run,usr,var,tmp,oldroot,lib}
mkdir /tmproot/usr/share/
cp -ax /{bin,etc,mnt,sbin,lib64} /tmproot/ > /dev/null 2>&1 || true
cp -ax /lib/!(modules|locale) /tmproot/lib/  > /dev/null 2>&1 || true
cp -ax /usr/{bin,sbin,lib64} /tmproot/usr/ > /dev/null 2>&1 || true
mkdir -p /tmproot/usr/lib
cp -ax /usr/lib/!(modules|locale) /tmproot/usr/lib/  > /dev/null 2>&1 || true
cp -ax /usr/share/ca-certificates /tmproot/usr/share/  > /dev/null 2>&1 || true
cp -ax /var/{account,empty,lib,local,lock,nis,opt,preserve,run,spool,tmp,yp} /tmproot/var/ > /dev/null 2>&1 || true
echo 20971520 > /proc/sys/vm/dirty_bytes
echo 5242880 > /proc/sys/vm/dirty_background_bytes
truncate -s 2G /tmproot/pre
LODEV=$(losetup -f)
losetup $LODEV /tmproot/pre
LODEV_SIZE=$((2*1073741824/512))
BLOCKDEV_SIZE=$(((10*1024*1024*1024)/512))
LODEV2=$(losetup -f)
losetup $LODEV2 /dev/$ROOT_DEV
echo "0 $LODEV_SIZE linear $LODEV 0
$LODEV_SIZE $BLOCKDEV_SIZE linear $LODEV2 $LODEV_SIZE" | dmsetup create repl
mount --make-rprivate /
pivot_root /tmproot /tmproot/oldroot
for i in dev proc sys run; do mount --move /oldroot/$i /$i; done
echo "Restarting services..."
systemctl daemon-reexec
systemctl restart rsyslog
systemctl restart ssh
kill -9 $(pidof dhclient) > /dev/null 2>&1 || true
systemctl stop unattended-upgrades > /dev/null 2>&1 || true
systemctl stop systemd-udevd > /dev/null 2>&1 || true
systemctl restart systemd-timesyncd > /dev/null 2>&1 || true
#systemctl restart dbus > /dev/null 2>&1 || true
systemctl restart atd > /dev/null 2>&1 || true
systemctl restart lvm2-lvmetad > /dev/null 2>&1 || true
systemctl restart lxcfs > /dev/null 2>&1 || true
systemctl restart accounts-daemon > /dev/null 2>&1 || true
systemctl restart networkd-dispatcher > /dev/null 2>&1 || true
systemctl restart polkit > /dev/null 2>&1 || true
systemctl restart serial-getty@ttyS0 > /dev/null 2>&1 || true
systemctl restart systemd-networkd > /dev/null 2>&1 || true
systemctl restart getty@tty1 > /dev/null 2>&1 || true
systemctl restart systemd-logind > /dev/null 2>&1 || true
systemctl restart cron > /dev/null 2>&1 || true
systemctl restart systemd-journald > /dev/null 2>&1 || true
systemctl restart ntp > /dev/null 2>&1 || true
systemctl restart systemd-resolved  > /dev/null 2>&1 || true
systemctl restart cloud-init-log-reader > /dev/null 2>&1 || true
systemctl restart rdnssd > /dev/null 2>&1 || true
pkill -9 "(sd-pam)" > /dev/null 2>&1 || true
mount -o remount,ro /oldroot
sync
! [ -e /oldroot/usr/sbin/sshd ] || cat /oldroot/usr/sbin/sshd > /dev/null
! [ -e /oldroot/lib/systemd/systemd-logind ] || cat /oldroot/lib/systemd/systemd-logind > /dev/null
! [ -e /oldroot/lib/systemd/systemd ] || cat /oldroot/lib/systemd/systemd > /dev/null
cat << "EOF" > /refresh_sshd.sh
set -e
while true; do
	for p in $(pidof sshd); do
                ! [ -f /oldroot$(readlink /proc/$p/exe) ] || cat /oldroot$(readlink /proc/$p/exe) > /dev/null
		for i in $(ls /proc/$p/map_files); do
			LOC=$(readlink /proc/$p/map_files/$i)
			! [ -f /oldroot$LOC ] || cat /oldroot$LOC > /dev/null
		done
        done
	touch /refresh_done
	sleep 1
done
EOF
bash /refresh_sshd.sh &
while ! [ -e /refresh_done ]; do
	sleep 1
done
echo "Replacing root file system on ${ROOT_DEV}... (DO NOT INTERRUPT FROM NOW ON)"
if [ "x$SET_RANDOM_ADMIN_PW" == "x1" ]
then
	echo -n "$LOGIN_PWD" > /login_pwd
fi

cat << "EOF" > /install_service.sh
ROOT_DEV=$(cat /root_dev)
if [ -e /login_pwd ]
then
	LOGIN_PWD=$(cat /login_pwd)
	echo "Replacing critical data... afterwards the appliance will be available after reboot. Please browse to http://INSTANCEIP and login with $LOGIN_PWD to finish setup."
else
	echo "Replacing critical data... afterwards the appliance will be available after reboot. Please browse to http://INSTANCEIP to finish setup."
fi
cat /pre > /dev/null
dd if=/pre of=/dev/$ROOT_DEV conv=notrunc,fsync bs=32M 2> /dev/null
if [ -e /login_pwd ]
then
	echo "Done replacing critical data. Rebooting instance. Appliance will be available after reboot. Please browse to http://INSTANCEIP and login with $LOGIN_PWD to finish setup."
else
	echo "Done replacing critical data. Shutting down instance. Instance will be available after start. Please browse to http://INSTANCEIP to finish setup."
fi
sleep 1
if [ -e /login_pwd ]
then
	if [ -e /proc/sysrq-trigger ]
	then
		echo b > /proc/sysrq-trigger
	else
		init 6
	fi
else
	if [ -e /proc/sysrq-trigger ]
	then
		echo o > /proc/sysrq-trigger
	else
		init 0
	fi
fi
EOF

cat << "EOF" > /lib/systemd/system/replace-critical.service
[Unit]
Description=Replace critical data

[Service]
ExecStart=/bin/bash /install_service.sh
User=root
EOF

cat << "EOF" > /install.sh
#!/bin/bash
set -e
IMG_URL="https://dl3.infscape.com/images/urbackup-app-10-13.img.zst"
ZSTD_URL="https://dl3.infscape.com/images/zstd"
LODEV=$(losetup -f)
ROOT_DEV=$(df -P /oldroot | tail -n 1 | awk '/.*/ { print $1 }' | sed "s@/dev/@@")
echo "Root partition: $ROOT_DEV"
if [ -e /sys/class/block/$ROOT_DEV/partition ]
then
        ROOT_DEV=$(basename "$(readlink -f "/sys/class/block/$ROOT_DEV/..")")
        echo "Root device: $ROOT_DEV"
fi
echo "$ROOT_DEV" > /root_dev
if command -v wget > /dev/null 2>&1
then
	wget "$ZSTD_URL" -O /usr/bin/zstd-cloud-deploy
	chmod +x /usr/bin/zstd-cloud-deploy
        wget "$IMG_URL" -O - | /usr/bin/zstd-cloud-deploy -d -c > /dev/mapper/repl
else
	curl "$ZSTD_URL" -o /usr/bin/zstd-cloud-deploy
	chmod +x /usr/bin/zstd-cloud-deploy
        curl "$IMG_URL" | /usr/bin/zstd-cloud-deploy -d -c > /dev/mapper/repl
fi
if [ -e /login_pwd ]
then
	echo "Mounting new file system..."
	mkdir -p /root_app

	losetup $LODEV /dev/mapper/repl --offset 110100480
	if ! mount $LODEV /root_app -o subvol=sys_root_current
	then
		dmesg | tail -n 10
		exit 1
	fi

	LOGIN_PWD=$(cat /login_pwd)
	mount $LODEV /root_app/var/urbackup -o subvol=urbackup
	echo 'if [ -e /var/urbackup/backup_server_settings.db ]; then' > /root_app/setup.sh
	echo 'COUNT_USERS=$(echo "SELECT COUNT(*) FROM si_users;" | sqlite3 /var/urbackup/backup_server_settings.db)' >> /root_app/setup.sh
	echo 'else' >> /root_app/setup.sh
	echo 'COUNT_USERS=0' >> /root_app/setup.sh
	echo 'fi' >> /root_app/setup.sh
	echo 'if [[ $COUNT_USERS == "0" ]]; then' >> /root_app/setup.sh
	echo "/usr/bin/urbackupsrv reset-admin-pw -p '$LOGIN_PWD' > /dev/null" >> /root_app/setup.sh
	echo 'fi' >> /root_app/setup.sh
	echo "Setting login password to $LOGIN_PWD..."
	chroot /root_app /bin/bash /setup.sh
	rm /root_app/setup.sh
	! [ -e /root_app/cloud-mode-set-admin-pw ] || rm /root_app/cloud-mode-set-admin-pw
	umount /root_app/var/urbackup
	umount /root_app
	sync
else
	sync
fi
systemctl start replace-critical
journalctl -u replace-critical -f
EOF
bash /install.sh

}

run
