#! /usr/bin/bash

#  This script is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License version 2 as
#  published by the Free Software Foundation.
#
#  See the COPYING and AUTHORS files for more details.

# unset posix strict conformance variable since patch cannot be run
# non-interactively when it's set.
unset POSIXLY_CORRECT

# unset GREP_OPTIONS as it's quite easy to break quilt with uncommon options
# see http://bugs.debian.org/715563
unset GREP_OPTIONS

export TEXTDOMAIN=quilt
export TEXTDOMAINDIR=/usr/share/locale

: ${QUILT_DIR=/usr/share/quilt}
export QUILT_DIR

if [ -z "$QUILTRC" ]
then
	for QUILTRC in $HOME/.quiltrc /etc/quilt.quiltrc; do
		[ -e $QUILTRC ] && break
	done
	export QUILTRC
fi

# Support compatibility layer
if [ -d $QUILT_DIR/compat ]
then
	export PATH="$QUILT_DIR/compat:$PATH"
fi

usage()
{

	echo $"Usage: quilt [--trace[=verbose]] [--quiltrc=XX] command [-h] ..."
	echo $"       quilt --version"

	echo $"Commands are:"
	quilt_commands \
	| sort \
	| column | column -t \
	| sed -e $'s/^/\t/'
	printf $"
Global options:

--trace
	Runs the command in bash trace mode (-x). For internal debugging.

--quiltrc file
	Use the specified configuration file instead of ~/.quiltrc (or
	%s/quilt.quiltrc if ~/.quiltrc does not exist).  See the pdf
	documentation for details about its possible contents.  The
	special value \"-\" causes quilt not to read any configuration
	file.

--version
	Print the version number and exit immediately.\n" "/etc"
	exit 1
}

quilt_commands()
{
	local command
	for command in $QUILT_DIR/*
	do
		if [ -f "$command" -a -x "$command" ]
		then
			echo ${command##$QUILT_DIR/}
		fi
	done
}

if [ $# -eq 1 -a "$1" == "--version" ]
then
	echo '0.66'
	exit
fi

BASH_OPTS=
while [ $# -ne 0 ]
do
	case $1 in
	[^-]*)
		if [ -z "$command" ]
		then
			command=$1
		else
			args[${#args[@]}]=$1
		fi ;;
	# Use a resource file other than ~/.quiltrc
	--quiltrc=*)
		QUILTRC=${1#--quiltrc=}
		[ "$QUILTRC" = - ] && unset QUILTRC ;;
	--quiltrc)
		QUILTRC=$2
		[ "$QUILTRC" = - ] && unset QUILTRC
		shift ;;
	# Trace execution of commands
	--trace*)
		BASH_OPTS="${BASH_OPTS:+$BASH_OPTS }-x"
		case "${1:7}" in
			'')
				;;
			=verbose)
				BASH_OPTS="${BASH_OPTS:+$BASH_OPTS }-v" ;;
			*)
				command=
				break ;;
		esac ;;
	*)
		args[${#args[@]}]=$1 ;;
	esac
	shift
done

if ! [ -f "$QUILT_DIR/$command" -a -x "$QUILT_DIR/$command" ]
then
	if [ -n "$command" ]
	then
		for arg in $(quilt_commands)
		do
			case "$arg" in
			$command*)
				commands[${#commands[@]}]=$arg
				;;
			esac
		done
		unset arg
	fi

	if [ ${#commands[@]} -eq 0 ]
	then
		usage
	elif [ ${#commands[@]} -eq 1 ]
	then
		command=${commands[0]}
		unset commands
	else
		echo "$command :" "${commands[@]}" >&2
		exit 1
	fi
fi

nsjail_config() {
	TMPFILE=$1
	mount_dir=$2
	cat <<END_CONFIG > $TMPFILE
	name: "quilt secure sandbox"

	description: "This policy allows to run quilt in a secure way"

	time_limit: 0

	cwd: "$(pwd)"
	envar: "HOME=$HOME"
	envar: "PATH=$PATH"
	envar: "EDITOR=$EDITOR"
	envar: "LC_CTYPE=$LC_CTYPE"
	envar: "LC_NUMERIC=$LC_NUMERIC"
	envar: "LC_TIME=$LC_TIME"
	envar: "LC_COLLATE=$LC_COLLATE"
	envar: "LC_MONETARY=$LC_MONETARY"
	envar: "LC_MESSAGES=$LC_MESSAGES"
	envar: "LC_PAPER=$LC_PAPER"
	envar: "LC_NAME=$LC_NAME"
	envar: "LC_ADDRESS=$LC_ADDRESS"
	envar: "LC_TELEPHONE=$LC_TELEPHONE"
	envar: "LC_MEASUREMENT=$LC_MEASUREMENT"
	envar: "LC_IDENTIFICATION=$LC_IDENTIFICATION"
	envar: "LC_ALL=$LC_ALL"
	envar: "TEXTDOMAIN=$TEXTDOMAIN"
	envar: "TEXTDOMAINDIR=$TEXTDOMAINDIR"
	envar: "QUILT_DIR=$QUILT_DIR"
	envar: "QUILTRC=$QUILTRC"
	envar: "QUILT_COMMAND=$QUILT_COMMAND"

	mount {
		src: "/bin"
		dst: "/bin"
		rw: false
		is_bind: true
	}
	mount {
		src: "/lib"
		dst: "/lib"
		rw: false
		is_bind: true
	}
	mount {
		src: "/lib64"
		dst: "/lib64"
		rw: false
		is_bind: true
	}
	mount {
		src: "/usr"
		dst: "/usr"
		rw: false
		is_bind: true
	}
	mount {
		src: "/sbin"
		dst: "/sbin"
		rw: false
		is_bind: true
	}
	mount {
		src: "/dev/null"
		dst: "/dev/null"
		rw: true
		is_bind: true
	}
	mount {
		src: "/etc/alternatives"
		dst: "/etc/alternatives"
		rw: false
		is_bind: true
	}
	mount {
		dst: "/tmp"
		fstype: "tmpfs"
		rw: true
		is_bind: false
	}
	mount {
		dst: "/var/tmp"
		fstype: "tmpfs"
		rw: true
		is_bind: false
	}
	mount {
		dst: "$HOME/rpmbuild"
		fstype: "tmpfs"
		rw: true
		is_bind: false
	}
	mount {
		src: "$mount_dir"
		dst: "$mount_dir"
		rw: true
		is_bind: true
	}

	rlimit_as_type: HARD
	rlimit_core_type: HARD
	rlimit_cpu_type: HARD
	rlimit_fsize_type: HARD
	rlimit_nofile_type: HARD
	rlimit_nproc_type: HARD
	rlimit_stack_type: HARD
END_CONFIG
	if [ -e "$QUILTRC" ]; then
	  cat <<END_CONFIG >> $TMPFILE
	mount {
		src: "$QUILTRC"
		dst: "$QUILTRC"
		rw: false
		is_bind: true
	}
END_CONFIG
	fi
}

set -- "${args[@]}"
unset args

export QUILT_COMMAND="${command##*/}"

if which nsjail >/dev/null 2>/dev/null; then
	mount_dir=$(pwd)
	if [ -L patches ]; then
	  # are we inside the already unpacked dir? If so mount the parent dir so we
	  # have access to the patches
	  mount_dir=$mount_dir/..
	fi

	# we need to create a temporary config file since mounts with
	# : don't work on the command line
	TMPFILE=`mktemp -t squilt.nsjail.XXXXXXXXXX` || exit 1
	trap "rm -f -- '$TMPFILE'" EXIT

	nsjail_config $TMPFILE $mount_dir

	nsjail -Mo -q --config $TMPFILE -- /bin/bash $BASH_OPTS -c ". $QUILT_DIR/$command" "quilt ${command##*/}" "$@"
else
	bash $BASH_OPTS -c ". $QUILT_DIR/$command" "quilt ${command##*/}" "$@"
fi
