#!/bin/ash
#
#  ovpkg - SquashFS package manager for OpenWrt-Zipit
#
#  Copyright (c) 2012 Joseph Honold <mozzwald@gmail.com>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.

# Display program name
echo "ovpkg - SquashFS package manager for OpenWrt-Zipit"

# include config file
if [ ! -f /etc/ovpkg.conf ]; then
	echo "ovpkg config missing /etc/ovpkg.conf"
	exit 1
fi
. /etc/ovpkg.conf

# setup/check some basics
if [ ! -d /tmp/ovpkg ]; then
	echo "Creating ovpkg temp dir"
	mkdir /tmp/ovpkg
	mkdir /tmp/ovpkg/packages
elif [ ! -d /tmp/ovpkg/packages ]; then
        echo "Creating ovpkg temp dir"
        mkdir /tmp/ovpkg/packages
fi
if [ -f /tmp/ovpkg/status ]; then
	touch /tmp/ovpkg/status
fi

case $1 in
	update)
		echo "Downloading package list from ${PKG_URL}"
		wget ${PKG_URL}/ovpackages -O - > ${PKG_LIST}
		if [ $? -ne 0 ]; then
			echo "ERROR: Unable to get updated package list"
		else
			echo "ovpkg listing updated successfully"
		fi
	;;
	list)
		# check for package list
		if [ ! -f "${PKG_LIST}" ]; then
			echo "Package info not available. Try: ovpkg update"
			exit 1
		fi

		# make sure we have a search term
		if [ -z $2 ]; then
#TODO: Ask to list all packages if no term provided or maybe list all packages anyway?
			echo "No search term provided. Try: ovpkg list <packagename>"
			exit 1
		else
			PKG_SEARCH=$2
		fi

		# get package info from the package list
		PKG_INFO=`grep -A 15 "Package: $PKG_SEARCH$" ${PKG_LIST} | grep -v "Provides:" | grep -v "Source:" | grep -v "Priority:" | grep -v "Maintainer" | grep -v "Installed-Size:" | grep -v "Status:"`
		if [ $? -ne 0 ]; then
			echo "Package '$PKG_SEARCH' not found. Please try again."
			exit 1
		fi
		echo -e "$PKG_INFO\n"
	;;
	mount)
		# Quit if we are already mounted
		STATUS=`cat /tmp/ovpkg/status`
		if [ $STATUS -eq 1 ]; then
			echo "overlay packages already mounted"
		exit 1
		fi

		# Mount squashfs packages to tmp dir
		for file in ${MMC_PKG_DIR}/*; do
			if [ -e "${file}" ]; then
				PKG_NAME=`echo $file | sed 's/\.ovpkg//' | sed 's/.*\///'`
				if [ ! -d "/tmp/ovpkg/packages/${PKG_NAME}" ]; then
					mkdir "/tmp/ovpkg/packages/${PKG_NAME}"
				fi
				echo "Mounting squashfs package: $PKG_NAME"
				mount -t squashfs -o noatime,ro $file "/tmp/ovpkg/packages/$PKG_NAME"
				#echo "Mounting package overlay: $PKG_NAME"
				mount -t overlayfs -o noatime,lowerdir=/tmp/ovpkg/packages/${PKG_NAME},upperdir=/overlay /tmp/ovpkg/packages/${PKG_NAME} /overlay
			fi
		done
		# Mount all dirs in overlay to rootfs
		for dir in /overlay/*; do
			CHK_ROOT_DIR=`echo $dir | sed 's/.*\///'`
			# Make dir in rootfs if it does not exist
			if [ ! -d "/${CHK_ROOT_DIR}" ]; then
				mkdir "/${CHK_ROOT_DIR}"
			fi
			echo "Mounting overlay dir to rootfs: /$CHK_ROOT_DIR"
			mount -t overlayfs -o noatime,lowerdir=${dir},upperdir=/${CHK_ROOT_DIR} ${dir} /${CHK_ROOT_DIR}
		done

		# Write status 1=mounted 0=not mounted
		echo 1 > /tmp/ovpkg/status
	;;
	umount)
		# Quit if we are not mounted
		STATUS=`cat /tmp/ovpkg/status`
		if [ $STATUS -eq 0 ]; then
        		echo "overlay packages not mounted"
        		exit 1
		fi
		# Unmount overlay dirs in rootfs
		for dir in /overlay/*; do
			if [ -d "${dir}" ]; then
				CHK_ROOT_DIR=`echo $dir | sed 's/.*\///'`
				echo "Unmounting overlay: $CHK_ROOT_DIR"
				umount /${CHK_ROOT_DIR}
        		fi
		done

		# Get count of mounts to /overlay
		OVCOUNT=`cat /proc/mounts | grep "/overlay" | wc -l`
		if [ $OVCOUNT -gt 0 ]; then
			echo "Unmounting /overlay $OVCOUNT times"
		fi

		# Unmount /overlay OVCOUNT times
		COUNTER=0
		while [ $COUNTER -lt $OVCOUNT ]; do
			let COUNTER=COUNTER+1
			echo "Unmounting /overlay $COUNTER"
			umount /overlay
		done
		# Unmount squashfs packages from tmp dir and remove dirs
		for dir in /tmp/ovpkg/packages/*; do
		if [ -d "${dir}" ]; then
			echo "Unmounting squashfs: $dir"
			umount ${dir}
			rm -rf ${dir}
		fi
		done                                                           

		# Write status 1=mounted 0=not mounted
		echo 0 > /tmp/ovpkg/status
	;;
	install)
		# check for package list
		if [ ! -f "${PKG_LIST}" ]; then
			echo "Package info not available. Try: ovpkg update"
			exit 1
		fi

		# make sure we have a package to install
		if [ -z $2 ]; then
			echo "No package name provided. Try: ovpkg install <packagename>"
			exit 1
		else
			PKG_SEARCH=$2
		fi

		# get package info from the package list
		PKG_INFO=`grep -A 15 "Package: $PKG_SEARCH$" ${PKG_LIST}`
		if [ $? -ne 0 ]; then
			echo "Package '$PKG_SEARCH' not found. Please try again."
			exit 1
		fi

		# check if package is installed via ovpkg OR opkg and same version
		PKG_NAME=`echo -e "$PKG_INFO" | grep "Package:" | sed 's/Package: //'`
		PKG_VER=`echo -e "$PKG_INFO" | grep "Version:" | sed 's/Version: //'`
		PKG_FILENAME=`echo -e "$PKG_INFO" | grep "Filename:" | sed 's/Filename: //'`
		PKG_MD5=`echo -e "$PKG_INFO" | grep "MD5Sum:" | sed 's/MD5Sum: //'`
		grep ${PKG_FILENAME} ${PKGS_INSTALLED} &> /dev/null
		if [ $? -eq 0 ]; then
			echo "Package '$PKG_NAME' is already installed as overlay package"
			#TODO: check if needs upgraded
			exit 1
		fi
		if [ -f /usr/lib/opkg/info/${PKG_NAME}.control ]; then         
			echo "Package '$PKG_NAME' is already installed as regular opkg"
			exit 1
		fi

		MOUNT_FILES="$PKG_FILENAME"

		# check dependencies and if they are installed
		PKG_DEPENDS=`echo -e "$PKG_INFO" | grep "Depends:" | sed 's/Depends: //' | sed 's/,//g'`
		DEPEND_COUNT=0
		for word in $PKG_DEPENDS; do
			DEPEND_INFO=`grep -A 15 "Package: $word" ${PKG_LIST}`
			# make sure we can satisfy the dependency
			if [ $? -ne 0 ]; then
				echo "Dependency $word cannot be satisfied."
				exit 1
			fi
			DEPEND_NAME=`echo -e "$DEPEND_INFO" | grep "Package:" | sed 's/Package: //'`
			DEPEND_VER=`echo -e "$DEPEND_INFO" | grep "Version:" | sed 's/Version: //'`
			DEPEND_FILENAME=`echo -e "$DEPEND_INFO" | grep "Filename:" | sed 's/Filename: //'`
			DEPEND_MD5=`echo -e "$DEPEND_INFO" | grep "MD5Sum:" | sed 's/MD5Sum: //'`
			# check for ovpkg first
			grep ${DEPEND_FILENAME} ${PKGS_INSTALLED} &> /dev/null
			if [ $? -ne 0 ]; then
				# check opkg
				if [ ! -f "/usr/lib/opkg/info/${DEPEND_NAME}.control" ]; then
					# save dependancy filename and md5 so we can install it
					eval DEPEND_FILENAME_$DEPEND_COUNT=\"$DEPEND_FILENAME\"
					eval DEPEND_MD5_$DEPEND_COUNT=\"$DEPEND_MD5\"
					eval DEPEND_NAME_$DEPEND_COUNT=\"$DEPEND_NAME\"
					let DEPEND_COUNT=$DEPEND_COUNT+1
					MOUNT_FILES="$MOUNT_FILES $DEPEND_FILENAME"
				else
					echo "Dependency $word already installed as regular opkg."
				fi
			else
				echo "Dependency $word already installed as ovpkg."
			fi
		done

		# download and install dependencies
		COUNTER=0
		while [ $COUNTER -lt $DEPEND_COUNT ]; do
			FILENAME=$( eval "echo \$DEPEND_FILENAME_$COUNTER" )
			MD5=$( eval "echo \$DEPEND_MD5_$COUNTER" )
			NAME=$( eval "echo \$DEPEND_NAME_$COUNTER" )
			rm -rf /tmp/$FILENAME
			wget $PKG_URL/$FILENAME -P /tmp
			if [ $? -ne 0 ]; then
				echo "ERROR Downloading package"
				exit 1
			fi
			# check md5sum
			DL_MD5=`md5sum /tmp/$FILENAME | sed 's/ .*//'`
			if [ "$DL_MD5" != "$MD5" ]; then
				echo "$FILENAME md5sum mismatch, exiting."
				exit 1
			fi
			mv /tmp/${FILENAME} ${MMC_PKG_DIR}
			echo ${FILENAME} >> ${PKGS_INSTALLED}
			let COUNTER=$COUNTER+1
			echo "$NAME installed successfully."
		done

		# download and install package
		rm -rf /tmp/$PKG_FILENAME
		wget $PKG_URL/$PKG_FILENAME -P /tmp
		if [ $? -ne 0 ]; then
			echo "ERROR Downloading package"
			exit 1
		fi
		# check md5sum
		DL_MD5=`md5sum /tmp/$PKG_FILENAME | sed 's/ .*//'`
		if [ "$DL_MD5" != "$PKG_MD5" ]; then
			echo "$PKG_FILENAME md5sum mismatch, exiting."
			exit 1
		fi
		mv /tmp/${PKG_FILENAME} ${MMC_PKG_DIR}
		echo ${PKG_FILENAME} >> ${PKGS_INSTALLED}
		echo "$PKG_NAME and dependencies installed successfully!"

		# if overlay is mounted, unmount it, mount packages and remount overlay
		STATUS=`cat /tmp/ovpkg/status`
		if [ $STATUS -eq 1 ]; then
			# Unmount overlay dirs in rootfs
			for dir in /overlay/*; do
				if [ -d "${dir}" ]; then
					CHK_ROOT_DIR=`echo $dir | sed 's/.*\///'`
					echo "Unmounting overlay: $CHK_ROOT_DIR"
					umount /${CHK_ROOT_DIR}
				fi
			done

			# mount newly installed ovpkgs
			for file in $MOUNT_FILES; do
				PKG_NAME=`echo $file | sed 's/\.ovpkg//' | sed 's/.*\///'`
				if [ ! -d /tmp/ovpkg/packages/${PKG_NAME} ]; then
					mkdir /tmp/ovpkg/packages/${PKG_NAME}
				fi
				echo "Mounting squashfs package: $PKG_NAME"
				mount -t squashfs -o noatime,ro ${MMC_PKG_DIR}/${file} /tmp/ovpkg/packages/${PKG_NAME}
				#echo "Mounting package overlay: $PKG_NAME"
				mount -t overlayfs -o noatime,lowerdir=/tmp/ovpkg/packages/${PKG_NAME},upperdir=/overlay /tmp/ovpkg/packages/${PKG_NAME} /overlay
			done

			# Mount all dirs in overlay to rootfs
			for dir in /overlay/*; do
				CHK_ROOT_DIR=`echo $dir | sed 's/.*\///'`
				# Make dir in rootfs if it does not exist
				if [ ! -d "/${CHK_ROOT_DIR}" ]; then
					mkdir "/${CHK_ROOT_DIR}"
				fi
				echo "Mounting overlay dir to rootfs: /$CHK_ROOT_DIR"
				mount -t overlayfs -o noatime,lowerdir=${dir},upperdir=/${CHK_ROOT_DIR} ${dir} /${CHK_ROOT_DIR}
			done
		fi
	;;
	remove)
		# make sure we have a package to remove
		if [ -z $2 ]; then
			echo "No package name provided. Try: ovpkg remove <packagename>"
			exit 1
		else
			PKG_SEARCH=$2
		fi

		# get package info from the package list
		PKG_INFO=`grep -A 15 "Package: $PKG_SEARCH$" ${PKG_LIST}`
		if [ $? -ne 0 ]; then
			echo "Package '$PKG_SEARCH' not found. Please try again."
			exit 1
		fi

		# check if package is installed
		PKG_NAME=`echo -e "$PKG_INFO" | grep "Package:" | sed 's/Package: //'`
		PKG_FILENAME=`echo -e "$PKG_INFO" | grep "Filename:" | sed 's/Filename: //'`
		grep ${PKG_FILENAME} ${PKGS_INSTALLED} &> /dev/null
		if [ $? -eq 0 ]; then
			# unmount overlay if needed
			STATUS=`cat /tmp/ovpkg/status`
			if [ $STATUS -eq 1 ]; then
				# Unmount overlay dirs in rootfs
				for dir in /overlay/*; do  
					if [ -d "${dir}" ]; then
						CHK_ROOT_DIR=`echo $dir | sed 's/.*\///'`
						echo "Unmounting overlay: $CHK_ROOT_DIR"
						umount /${CHK_ROOT_DIR}
					fi
				done

				# unmount squashfs package
				MOUNT_NAME=`echo $PKG_FILENAME | sed 's/.ovpkg//'`
				LOOP_DIR=`grep "$MOUNT_NAME" /proc/mounts | grep "squashfs" | sed 's/ \/tmp\/ovpkg\/packages.*//'`
				echo "$MOUNT_NAME $LOOP_DIR"
				umount /tmp/ovpkg/packages/${MOUNT_NAME}
				umount ${LOOP_DIR}
				rm -rf /tmp/ovpkg/packages/${MOUNT_NAME}

				# delete squashfs file and remove from installed list
				rm ${MMC_PKG_DIR}/${PKG_FILENAME}
				grep -v ${PKG_FILENAME} ${PKGS_INSTALLED} > /tmp/ovpkg/installed.list
				mv /tmp/ovpkg/installed.list /usr/lib/ovpkg/installed.list

				# remount overlay dirs
				for dir in /overlay/*; do
					CHK_ROOT_DIR=`echo $dir | sed 's/.*\///'`
					echo "Mounting overlay dir to rootfs: $CHK_ROOT_DIR"
					mount -t overlayfs -o noatime,lowerdir=${dir},upperdir=/${CHK_ROOT_DIR} ${dir} /${CHK_ROOT_DIR}
				done
			fi
		else
			echo "Package $PKG_SEARCH not installed."
			exit 1
		fi
	;;
	*)
		# Display some help
		echo "Usage: ovpkg <option>"
		echo -e "\tupdate                  Updates package listing from server"
		echo -e "\tinstall <packagename>   Installs package and dependencies"
		echo -e "\tremove <packagename>    Removes a package"
		echo -e "\tlist <packagename>      Displays package details"
		echo -e "\tmount                   Mounts packages to rootfs"
		echo -e "\tumount                  Unmounts packages from rootfs"
	;;
esac
