#!/bin/sh
#This script can help repeat one program within a package with the help of chroot.
package_path=""
mountlist=""
show_help()
{
	echo "Usage: chroot_package_run --package-path path-of-package [command]"
	echo "If no command is given, a /bin/sh shell will be returned."
	echo "Example 1: chroot_package_run --package-path /tmp/pack"
	echo "If one command is given, run your command within the chroot jail and exit chroot_package_run automatically."
	echo "Example 2: chroot_package_run --package-path /tmp/pack ls"
	echo ''
	echo "Options:"
	echo "-p, --package-path         The path of the package."
	echo "-e, --env-list             The path of the environment file, each line is in the format of <key>=<value>. (Default: package-path/env_list)"
	echo "-h, --help                 Show this help message."
	exit 1
}

complete_path() {
	orig_path="$1"
	first_ch=$(echo "${orig_path}" | head -c 1)
	if [ "${first_ch}" != "/" ]; then
		echo "$(pwd)/${orig_path}"
	else
		echo "${orig_path}"
	fi
}

while [ "$#" -gt 0 ]
do
	case "$1" in
		-p | --package-path)
			shift
			package_path="$(complete_path "$1")"
			;;
		-e | --env-list)
			shift
			env_path="$(complete_path "$1")"
			;;
		-h | --help)
			show_help
			;;
		*)
			break
			;;
	esac
	shift
done

if [ -n "${env_path}" ] && [ ! -f "${env_path}" ]; then
	echo "The --env-list option specified (${env_path}) is not a file!"
	exit 1
fi

if [ -z "${env_path}" ]; then
	env_path="${package_path}/env_list"
	if [ ! -f "${env_path}" ]; then
		echo "Warning: you are going to use the environment variable settings from your current shell to run your package."
		echo "         You can specify an environment variable list file with the --env-list option."
	fi
fi


if [ -z "${package_path}" ]; then
	echo "Please specify package-path!"
	exit 1
fi

if [ ! -d "${package_path}" ]; then
	echo "Please ensure directory ${package_path} exists!"
	exit 1
fi

user=$(whoami)
if [ ! "${user}" = "root" ]; then
	echo "chroot_package_run needs the root account!!"
	exit 1
fi

package_path=$(readlink -f "${package_path}")
cd "${package_path}"

cmd_chroot=$(which chroot)
cmd_rm=$(which rm)
cmd_umount=$(which umount)
cmd_rmdir=$(which rmdir)

if [ -z "${cmd_chroot}" ]; then
	echo "Can't not find chroot! Please add the path of chroot into PATH environment variables!"
	exit 1
fi

if [ -z "${cmd_rm}" ]; then
	echo "Can't not find rm! Please add the path of rm into PATH environment variables!"
	exit 1
fi

if [ -z "${cmd_umount}" ]; then
	echo "Can't not find umount! Please add the path of umount into PATH environment variables!"
	exit 1
fi

if [ -z "${cmd_rmdir}" ]; then
	echo "Can't not find rmdir! Please add the path of rmdir into PATH environment variables!"
	exit 1
fi

common_mountlist="${package_path}/common-mountlist"
#umount chroot dirs
unmount_virtual_fs() {
	while read item
	do
		tmp_fs=$(echo "${item}"|cut -d' ' -f1)
		virtual_fs="${package_path}/${tmp_fs}"
		if [ -e "${virtual_fs}" ]; then
			"${cmd_umount}" -f "${virtual_fs}" 1>/dev/null 2>/dev/null
			"${cmd_rmdir}" "${virtual_fs}"
		fi
	done <"${common_mountlist}"
}

#remove special files
remove_special_files() {
	if [ -e "${package_path}/etc/resolv.conf" ]; then
		"${cmd_rm}" "${package_path}/etc/resolv.conf"
	fi
	while read line
	do
		item=$(echo "${line}"|cut -d' ' -f1)
		if [ -e "${package_path}/${item}" ]; then
			unlink "${package_path}/${item}"
		fi
	done < "${package_path}/special_files"
}

if [ -f "${common_mountlist}" ]; then
	unmount_virtual_fs
fi

if [ -f "${package_path}/special_files" ]; then
	remove_special_files
fi

# This allows DNS lookups via your system's networking
if [ ! -e etc ]; then
	mkdir etc
fi
cp -L /etc/resolv.conf etc/

if [ -f "${common_mountlist}" ]; then
	while read item
	do
		tmp_fs=$(echo "${item}"|cut -d' ' -f1)
		virtual_fs="./${tmp_fs}"
		mkdir -p "${virtual_fs}" 1>/dev/null 2>/dev/null
		mount --bind "${tmp_fs}" "${virtual_fs}" 1>/dev/null 2>/dev/null
	done <"${common_mountlist}"
fi

#create hardlink to special files
if [ -f "${package_path}/special_files" ]; then
	while read line
	do
		item=$(echo "${line}"|cut -d' ' -f1)
		if [ -e "${package_path}/${item}" -o ! -e "${item}" ]; then
			continue
		fi
		filename=$(basename "${item}")
		filepath="${item%filename}"
		if [ ! -e "${package_path}/${filepath}" ]; then
			mkdir -p "${package_path}/${filepath}"
		fi
		cd "${ackage_path}/${filepath}"
		ln "${item}" "${filename}"
		if [ ! "$?" -eq 0 ]; then
			echo "Creating hardlink to special file (${item}) failed."
		fi
	done < "${package_path}/special_files"
fi

cd "${package_path}"

#import environment varibales
export_env() {
	while read line
	do
		IFS="="     # Set the field separator
		set ${line}      # Breaks the string into $1, $2, ...
		variable_name="$1"
		name_len="${#variable_name}"
		name_len=$(expr "${name_len}" + 1)
		variable_value="${line:name_len}"
		export "${variable_name}"="${variable_value}"
		IFS=" "
	done < "${env_path}"
}

if [ -f "${env_path}" ]; then
	export_env
fi

export PACKAGE_CHROOT_PWD="${PWD}"
if [ -z "$1" ]; then
	"${cmd_chroot}" "${package_path}" /bin/sh -c 'cd "${PACKAGE_CHROOT_PWD}"; exec /bin/sh'
else
	"${cmd_chroot}" "${package_path}" /bin/sh -c 'cd "${PACKAGE_CHROOT_PWD}"; exec "$@"' -- "$@"
fi

#post cleaning process
if [ -f "${common_mountlist}" ]; then
	unmount_virtual_fs
fi

if [ -f "${package_path}/special_files" ]; then
	remove_special_files
fi
