#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (c) 2019-2020, AT&T Intellectual Property.
# All Rights Reserved.

# Running version of Vyatta
: ${vyatta_prefix:=/opt/vyatta}
: ${vyatta_exec_prefix:=$vyatta_prefix}
: ${vyatta_bindir:=${vyatta_exec_prefix}/bin}
: ${vyatta_sbindir:=${vyatta_exec_prefix}/sbin}
export PATH="$PATH:${vyatta_sbindir}:${vyatta_bindir}"

source ${vyatta_sbindir}/vyatta-install-image.functions
source ${vyatta_sbindir}/vyatta-live-image.functions

# Additonal debug logging
export INSTALL_LOG=/var/log/vyatta/squash-chroot.log
declare -i MOUNTED=0

safe_umount ()
{
	[[ $MOUNTED -eq 0 ]] && return
	umount $merged/proc &>/dev/null
	umount $merged/dev/pts &>/dev/null
	umount $merged/dev &>/dev/null
	umount $merged &>/dev/null
	umount $lower_dir &>/dev/null
	rmdir $merged &>/dev/null
	rmdir $lower_dir &>/dev/null
	unset merged &>/dev/null
	unset lower_dir &>/dev/null
}
trap "{ safe_umount; }" EXIT HUP KILL

apt_command ()
{
	aptcmd=${1:?Missing Command}
	chroot ${merged} rm stdout stderr &>/dev/null
	if ! run_command chroot ${merged} /bin/bash -c \
		"DEBIAN_FRONTEND=noninteractive ${aptcmd} >stdout 2>stderr"; then
		echo "Fatal error detected running apt-get update!"
		return 1
	fi

	if grep -q '^[E]:' "${merged}/stderr"; then
		echo "Apt-get failed."
		cat "${merged}/stderr"
		return 1
	fi
	
	# Apt-get was successful at this point, but may have run into dependency
	# issues. Print stdout regardless.
	cat ${merged}/stdout

	if grep -q '^[W]:' "${merged}/stderr"; then
		echo "Apt-get succeeded but with warnings."
		cat "${merged}/stderr"
	fi

	if grep -q '[1-9]\d* not upgraded' "${merged}/stdout"; then
		echo "Apt-get failed to install some packages"
		return 1
	fi

	return 0
}

get_running_image() {
	PERL5LIB=/opt/vyatta/share/perl5 \
		perl -MVyatta::Live -E "print get_running_image()"
}


TARGET_IMAGE=${1//[^a-zA-Z0-9\_\.\-]/}
if [[ -z $TARGET_IMAGE ]]; then
	fail_exit "No target image provided"
fi

# COMMANDS:
#   INSTALL
#   LIST
COMMAND=${2//[^a-zA-Z0-9]/}
if [[ -z $COMMAND ]]; then
	fail_exit "No command provided"
fi

lecho "Starting Vyatta Overlay mounter"

ROOTFS_DEV=$(what_is_mounted_on /boot)
if [[ -z $ROOTFS_DEV ]]; then
	logger error "$0: Failed to get root device for $TARGET_IMAGE"
	fail_exit "Failed to get root device for $TARGET_IMAGE"
fi

RUNNING_IMAGE=$(get_running_image)

if [[ $RUNNING_IMAGE != $TARGET_IMAGE ]]; then
	MOUNTED=1
	#
	# Setup Overlay
	squashfs=/lib/live/mount/persistence/${ROOTFS_DEV##*/}/boot/${TARGET_IMAGE}/${TARGET_IMAGE}.squashfs
	if [[ ! -f $squashfs ]]; then
		base="/lib/live/mount/persistence/${ROOTFS_DEV##*/}/boot/${TARGET_IMAGE}/"
		curr=$(pwd)
		cd $base
		eval squashfs=*.squashfs
		squashfs=${base}${squashfs}
		cd $curr
	fi

	export merged=/mnt/merged
	export lower_dir=/mnt/squash
	upper_dir=/lib/live/mount/persistence/${ROOTFS_DEV##*/}/boot/${TARGET_IMAGE}/persistence/rw
	work_dir=/lib/live/mount/persistence/${ROOTFS_DEV##*/}/boot/${TARGET_IMAGE}/persistence/work

	mkdir -p $lower_dir
	mkdir -p $merged

	if ! try_mount $squashfs $lower_dir; then
		safe_umount
		logger error "$0: Failed to mount target squashfs"
		fail_exit "Failed to mount target squashfs"
	fi

	margs="-t overlay -o noatime,upperdir=${upper_dir},lowerdir=${lower_dir},workdir=${work_dir} overlay $merged"
	if ! try_mount $margs; then
		safe_umount
		logger error "$0: Cannot mount overlay"
		fail_exit "Cannot mount overlay"
	fi
	lecho "Successfully set up overlay dir."
fi

if [[ $COMMAND == "LIST" ]]; then
	declare -a dpkg_cmd=(dpkg --list)
	if [[ $MOUNTED -eq 1 ]]; then
		dpkg_cmd[2]="--root=${merged}"
	fi
	run_command "${dpkg_cmd[@]}"
	ret=$?
elif [[ $COMMAND == "INSTALL" ]]; then
	if [[ $MOUNTED -eq 0 ]]; then
		logger error "$0: Can't INSTALL on running image"
		fail_exit "Can't INSTALL on running image"
	fi
	if [[ -z $VYATTA_NEW_PKGS ]]; then
		safe_umount
		logger error "$0: No packages specified for install"
		fail_exit "No packages specified for install"
	fi

	for pkg in $VYATTA_NEW_PKGS; do
		if [[ ! -f $pkg ]]; then
			safe_umount
			logger error "$0: Package not found: $pkg"
			fail_exit "Package not found: $pkg"
		fi
	done

	if ! try_mount --bind /dev ${merged}/dev; then
		fail_exit "Failed to setup chroot"
	fi
	if ! try_mount --bind /dev/pts ${merged}/dev/pts; then
		fail_exit "Failed to setup chroot"
	fi
	if ! try_mount --bind /proc ${merged}/proc; then
		fail_exit "Failed to setup chroot"
	fi

	# Set up repo
	TEMP_APT_REPO_DIR=/var/UPSTREAM
	mkdir -p ${merged}${TEMP_APT_REPO_DIR}
	run_command cp $VYATTA_NEW_PKGS ${merged}${TEMP_APT_REPO_DIR}/
	pushd ${merged}${TEMP_APT_REPO_DIR}/ &>/dev/null
	run_command dpkg-scanpackages ./ 2>/dev/null > ./Packages
	if [[ $? != 0 ]]; then
		safe_umount
		logger error "$0: Failed to scan packages"
		fail_exit "Failed to scan packages"
	fi
	popd &>/dev/null
	chown -R _apt:root ${merged}${TEMP_APT_REPO_DIR}
	chmod -R 700 ${merged}${TEMP_APT_REPO_DIR}

	# Create and clear apt sources just in case there are lingering build
	# time sources.
	mkdir -p ${merged}/etc/apt/sources.list.d
	echo > ${merged}/etc/apt/sources.list


	cat > ${merged}/etc/apt/sources.list.d/hotfix.list << EOF
deb file:${TEMP_APT_REPO_DIR} ./
EOF

	# Run apt-get upgrade
	APT_ARGS="--allow-downgrades --allow-remove-essential --allow-change-held-packages"
	apt_command "apt-get update"
	if [[ $? != 0 ]]; then
		safe_umount
		logger error "$0: Apt-get update failed"
		fail_exit "Apt-get update failed"
	fi
	apt_command "apt-get $APT_ARGS --yes --dry-run upgrade"
	if [[ $? != 0 ]]; then
		safe_umount
		logger error "$0: Apt-get dry run failed"
		fail_exit "Apt-get dry run failed"
	fi
	apt_command "apt-get $APT_ARGS --yes dist-upgrade"
	if [[ $? != 0 ]]; then
		safe_umount
		logger error "$0: Apt-get upgrade failed"
		fail_exit "Apt-get upgrade failed"
	fi
	run_command chroot ${merged} rm stderr stdout
	run_command rm -rf ${merged}/${TEMP_APT_REPO_DIR}
	run_command rm -rf ${merged}/etc/apt/sources.list.d/hotfix.list
	run_command chroot ${merged} /bin/bash -c \
		"DEBIAN_FRONTEND=noninteractive apt-get clean"
else
	safe_umount
	fail_exit "Command [$COMMAND] not supported"
fi

safe_umount
exit $ret
