#  empdebuild : shell library to support building chroots for Emdebian.
#
#  Copyright (C) 2006-2008  Neil Williams <codehelp@debian.org>
#  Copyright (C) 2001-2007 Junichi Uekawa
#
#  This package 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 3 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.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

# This shell library requires perl and pbuilder!

# Intended solely for use on the build machine. Do not use these functions
# in second_stage_install !

. /usr/lib/pbuilder/pbuilder-modules

OURVERSION=`perl -e 'use Emdebian::Tools; print &tools_version();'`

function get_default_arch ()
{
	ARCH=`perl -e 'use Debian::DpkgCross; \
&read_config(); \
my $arch = &get_architecture(); \
print (qq/None.\n/) if (!$arch); \
print $arch;';`
}

function get_work_dir ()
{
	WORKDIR=`perl -e 'use Cwd; use Emdebian::Tools; use Config::Auto; use Debian::DpkgCross; \
&read_config; \
my $w = &get_workdir; \
$w = cwd if (! -d $w); \
$w =~ s/\/$//; \
print $w;';`
}

get_work_dir
get_default_arch

WORKPLACE="${WORKDIR}/pbuilder"
BASETGZ="${WORKDIR}/emdebian.tgz"

#pbuilder base values
DEBIAN_BUILDARCH=$ARCH
# cross-building chroot is same arch as host.
BUILDRESULT="$WORKPLACE/result/"
# tidy up // to /
BUILDRESULT=`echo $BUILDRESULT | tr -s \/`
APTCACHE="$WORKPLACE/aptcache/"
# tidy up // to /
APTCACHE=`echo $APTCACHE | tr -s \/`
AUTO_DEBSIGN=yes
APTCACHEHARDLINK="no"
BUILDPLACE="$WORKPLACE/build"

# the default is to add a PID in the buildplace.
BASEBUILDPLACE="$BUILDPLACE"
if [ "${PRESERVE_BUILDPLACE}" != "yes" ]; then
    BUILDPLACE="$BUILDPLACE/$$"
fi

function checkarch ()
{
	ARCH=$ARCH perl -e 'use Debian::DpkgCross; $arch = $ENV{ARCH}; $arch=~s/ //g; \
		die "Unsupported architecture: $arch Use --arch\n" if (not defined (&check_arch($arch)));'
}

function extractembuildplace () {
	# after calling this function, umountproc, and cleanbuildplace
	# needs to be called. Please trap it.
	if [ ! \( "${PRESERVE_BUILDPLACE}" = "yes" -a -d "$BUILDPLACE" \) ]; then
		cleanbuildplace
		echo "Building the Emdebian build Environment"
		if ! mkdir -p "$BUILDPLACE"; then
		    echo "E: failed to build the directory to chroot"
		    exit 1
		fi
		echo " -> extracting base tarball [${BASETGZ}]"
		if [ ! -f "$BASETGZ" ]; then
		    echo "E: failed to find $BASETGZ, have you created your base tarball yet?"
		    exit 1
		fi
		if ! (cd "$BUILDPLACE" && tar xfzp "$BASETGZ"); then
		    echo "E: failed to extract $BASETGZ to $BUILDPLACE"
		    exit 1
		fi
		echo " -> creating local configuration"
		if [ $CROSS -a $CROSS != $ARCH ]; then
			hostname -f > "$BUILDPLACE/etc/mailname"
		else
			echo "emdebian-$ARCH" > "$BUILDPLACE/etc/mailname"
		fi
		if [ ! -f "$BUILDPLACE/etc/apt/apt.conf.d/10disablerecommends" ]; then
			disable_apt_recommends
		fi
	fi
	copy_local_configuration
	mountproc
	mkdir -p "$BUILDPLACE/tmp/buildd"

	if [ "$OVERRIDE_APTLINES" = "yes" ]; then
		installaptlines
	fi
}

function autoclean_aptcache() {
	if [ -n "$APTCACHE" ]; then
	echo " -> Cleaning the cached apt archive"
	chroot $BUILDPLACE /usr/bin/apt-get autoclean || true
	find "$APTCACHE/" -maxdepth 1 -name \*.deb | \
	while read A; do
		if [ ! -f "$BUILDPLACE/var/cache/apt/archives/"$(basename "$A") -a \
		-f "$A" ]; then
		echo " -> obsolete cache content "$(basename "$A")" removed"
		rm -f "$A" || true
		fi
	done
	fi
}

function create_emdebiantgz() {
	# create base.tgz
	(
	if ! cd "$BUILDPLACE"; then
		echo "Error: unexpected error in chdir to $BUILDPLACE" >&2
		exit 1;
	fi
	while test -f "${BASETGZ}.tmp"; do
		echo "  -> Someone else has lock over ${BASETGZ}.tmp, waiting"
		sleep 10s
	done
	echo " -> creating base tarball [${BASETGZ}]"
	if ! sudo tar cfz "${BASETGZ}.tmp" * ; then
	    echo " -> failed building base tarball"
	    rm -f "${BASETGZ}.tmp"
	    exit 1;
	fi
	mv "${BASETGZ}.tmp" "${BASETGZ}"
    )
}

function check_dirs()
{
	if [ ! -d $BUILDPLACE ] ; then
		mkdir -p $BUILDPLACE
	fi
	if [ ! -d $BUILDRESULT ] ; then
		mkdir -p $BUILDRESULT
	fi
	if [ ! -d $APTCACHE ] ; then
		mkdir -p $APTCACHE
	fi
}

function disable_apt_recommends () {
	if [ -d "$BUILDPLACE/etc/apt/apt.conf.d/" ]; then
		if [ ! -f "$BUILDPLACE/etc/apt/apt.conf.d/10disablerecommends" ]; then
			echo "  -> disabling Apt::Install-Recommends"
			echo \
"APT
{
  Install-Recommends \"false\"
};
" > $BUILDPLACE/etc/apt/apt.conf.d/10disablerecommends
		fi
	fi
}

# intended only for chroots
function copy_host_configuration () {
	echo " -> copying local configuration"
	if [ $CROSS -a $CROSS != $ARCH ]; then
	    for a in hosts hostname resolv.conf; do
			sudo rm -f "$BUILDPLACE/etc/$a"
			if [ ! -f "/etc/$a" ]; then
			    echo "E: /etc/$a does not exist, your setup is insane. fix it" >&2
			sudo cp $( readlink -f "/etc/$a" ) "$BUILDPLACE/etc/$a";
			fi
		done
	else
	# sandboxes need a different hostname
	mkdir -p "$BUILDPLACE"/etc/
	cat > "$BUILDPLACE"/etc/hostname << EOF
emdebian-$ARCH
EOF
	fi
}

function unpack_debootstrap () {
	info INSTCORE "Starting unpacking in $BUILDPLACE"
	for deb in `ls $BUILDPLACE/var/cache/apt/archives/*.deb`; do
		ver=`dpkg -f $deb Version`
		pkg=`dpkg -f $deb Package`
		info INSTCORE "Unpacking $pkg ($ver) ...."
		dpkg -x $deb $BUILDPLACE/
		# get the package listing with reduced parsing complexity
		mkdir $BUILDPLACE/listing
		ar -p $deb data.tar.gz > $BUILDPLACE/listing/data.tar.gz
		tar -tzf $BUILDPLACE/listing/data.tar.gz | sed -e 's/^\.//' | sed -e 's/^\/$/\/\./' | sed -e 's/\/$//' > $BUILDPLACE/var/lib/dpkg/info/${pkg}.list
		rm -rf $BUILDPLACE/listing
		rm -rf $BUILDPLACE/tmp/*
		dpkg -e $deb $BUILDPLACE/tmp/
		for maint in `ls $BUILDPLACE/tmp/`; do
			mv $BUILDPLACE/tmp/$maint $BUILDPLACE/var/lib/dpkg/info/$pkg.$maint
			if [ $maint = "control" ]; then
				cat $BUILDPLACE/var/lib/dpkg/info/$pkg.$maint >> $BUILDPLACE/var/lib/dpkg/available
				cat $BUILDPLACE/var/lib/dpkg/info/$pkg.$maint >> $BUILDPLACE/var/lib/dpkg/status
				echo "" >> $BUILDPLACE/var/lib/dpkg/available
				echo "Status: install ok unpacked" >> $BUILDPLACE/var/lib/dpkg/status
				rm $BUILDPLACE/var/lib/dpkg/info/$pkg.$maint
			fi
		done
		if [ -f $BUILDPLACE/var/lib/dpkg/info/$pkg.conffiles ]; then
			echo "Conffiles:" >> $BUILDPLACE/var/lib/dpkg/status
			info INSTCORE "Processing $pkg.conffiles"
			for line in `cat $BUILDPLACE/var/lib/dpkg/info/$pkg.conffiles`; do
				md5=`md5sum $BUILDPLACE/$line | cut -d" " -f1`
				echo " $line $md5" >> $BUILDPLACE/var/lib/dpkg/status
			done
		fi
		echo "" >> $BUILDPLACE/var/lib/dpkg/status
	done
	# busybox symlinks are best managed in postinst so that dpkg
	# does not complain when they are replaced by Debian packages.
	# this allows more applets to be supported by default.
	if [ -f $BUILDPLACE/usr/share/busybox/busybox.links ]; then
		cd $BUILDPLACE
		# setup busybox
		cp usr/share/busybox/busybox.links .
		cp usr/share/busybox/install.sh .
		# link in the rest of its applets from OUTSIDE the chroot
		info INSTCORE "Symlinking the busybox applets..."
		sh ./install.sh $BUILDPLACE/ --symlinks
		rm $BUILDPLACE/install.sh
		rm $BUILDPLACE/busybox.links
	else
		info INSTCORE "busybox configuration not required"
	fi
	if [ ! -e "$BUILDPLACE/etc/localtime" ]; then
		ln -sf /usr/share/zoneinfo/UTC "$BUILDPLACE/etc/localtime"
	fi
	# a better fix for /usr/sbin/update-rc.d is available via sysv-rc
	if [ ! -f $BUILDPLACE/usr/sbin/update-rc.d ]; then
		echo "#!/bin/sh" > $BUILDPLACE/usr/sbin/update-rc.d
		echo "" >> $BUILDPLACE/usr/sbin/update-rc.d
		chmod 755 $BUILDPLACE/usr/sbin/update-rc.d
	fi
	RC=`head $BUILDPLACE/usr/sbin/update-rc.d | grep /usr/bin/perl || true`
	if [ "$RC" != "" ]; then
		info INSTCORE "Replacing perl update-rc.d"
		echo "#!/bin/sh" > $BUILDPLACE/usr/sbin/update-rc.d
		echo "" >> $BUILDPLACE/usr/sbin/update-rc.d
		chmod 755 $BUILDPLACE/usr/sbin/update-rc.d
	fi
	# invoke-rc.d is usually shell but is being looked at in Debian.
	if [ ! -f $BUILDPLACE/usr/sbin/invoke-rc.d ]; then
		echo '#!/bin/sh' > $BUILDPLACE/usr/sbin/invoke-rc.d
		echo 'exec /etc/init.d/$1 $2' > $BUILDPLACE/usr/sbin/invoke-rc.d
		echo '' >> $BUILDPLACE/usr/sbin/invoke-rc.d
		chmod 755 $BUILDPLACE/usr/sbin/invoke-rc.d
	fi
	info INSTCORE "Removing archives..."
	rm -f $BUILDPLACE/var/cache/apt/archives/*.deb
	# (skip stages in emsecondstage)
	touch $BUILDPLACE/debootstrap/unpacked
}

function extra_etc_rcd ()
{
	if [ ! -d $BUILDPLACE/etc/rcS.d ]; then
		mkdir $BUILDPLACE/etc/rcS.d
	fi
	if [ ! -d $BUILDPLACE/etc/rc0.d ]; then
		mkdir $BUILDPLACE/etc/rc0.d
	fi
	if [ ! -d $BUILDPLACE/etc/rc1.d ]; then
		mkdir $BUILDPLACE/etc/rc1.d
	fi
	if [ ! -d $BUILDPLACE/etc/rc6.d ]; then
		mkdir $BUILDPLACE/etc/rc6.d
	fi
}

function provide_var_lib_x11 ()
{
	if [ ! -d $BUILDPLACE/var/lib/X11 ]; then
		mkdir -p $BUILDPLACE/var/lib/X11
	fi
}

# unpack_debootstrap should have already been run
# This routine simply puts in a default if none exists.
function basic_group_setup () {
	if [ ! -f $BUILDPLACE/etc/group ]; then
		echo \
"root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
lp:x:7:
mail:x:8:
news:x:9:
uucp:x:10:
man:x:12:
proxy:x:13:
kmem:x:15:
audio:x:29:
utmp:x:43:
video:x:44:
" > $BUILDPLACE/etc/group
	fi
}

# unpack_debootstrap should have already been run
# This routine simply puts in a default if none exists.
function basic_passwd_setup () {
	if [ ! -f $BUILDPLACE/etc/passwd ]; then
		echo \
"root:x:0:0:root:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
" > $BUILDPLACE/etc/passwd
	fi
}

# need /etc/shadow too
function basic_shadow_setup () {
	if [ ! -f $BUILDPLACE/etc/shadow ]; then
		echo \
"root:$1$Vu4M34LT$0L2BfH9nXbSG1zQWxUH8M1:0::::::
daemon:*:13896:0:99999:7:::
bin:*:0:0:99999:7:::
sys:*:0:0:99999:7:::
sync:*:0:0:99999:7:::
games:*:0:0:99999:7:::
man:*:0:0:99999:7:::
lp:*:0:0:99999:7:::
mail:*:0:0:99999:7:::
news:*:0:0:99999:7:::
uucp:*:0:0:99999:7:::
proxy:*:0:0:99999:7:::
www-data:*:0:0:99999:7:::
backup:*:0:0:99999:7:::
list:*:0:0:99999:7:::
irc:*:0:0:99999:7:::
gnats:*:0:0:99999:7:::
nobody:*:0:0:99999:7:::" > $BUILDPLACE/etc/shadow
	fi
}

function provide_empty_install_info () {
	if [ ! -f $BUILDPLACE/usr/sbin/install-info ]; then
	echo \
'#!/bin/sh
exec /etc/init.d/$1 $2
' > $BUILDPLACE/usr/sbin/install-info
	chmod 755 $BUILDPLACE/usr/sbin/install-info
	fi
}

function set_approx_time () {
	if [ -d $BUILDPLACE/bin ]; then
		DATE=`date`
		ZERO=`date -d@0`
		# if we have a usable date, store it.
		if [ "$DATE" != "$ZERO" ]; then
			APPROX=`stat -c%Y $BUILDPLACE/bin/`
			STR=`date -d@$APPROX +%m%d%H%M%Y`
			info INSTCORE "Storing approximate time '$STR' in './datestring'"
			echo "$STR" > $BUILDPLACE/datestring
		fi
	fi
}

function basic_etc_fstab () {
	if [ ! -f "$BUILDPLACE/etc/fstab" ]; then
		echo '# /etc/fstab: static file system information.' > "$BUILDPLACE/etc/fstab"
		echo '#' >> "$BUILDPLACE/etc/fstab"
		echo '# <file system> <mount point>   <type>  <options>       <dump>  <pass>' >> "$BUILDPLACE/etc/fstab"
		echo 'proc            /proc           proc    defaults        0       0' >> "$BUILDPLACE/etc/fstab"
		echo 'sysfs           /sys            sysfs   defaults        0       0' >> "$BUILDPLACE/etc/fstab"
		echo 'devpts          /dev/pts        devpts  mode=0620,gid=5 0       0' >> "$BUILDPLACE/etc/fstab"
		chown 0.0 "$BUILDPLACE/etc/fstab"; chmod 644 "$BUILDPLACE/etc/fstab"
	fi
}

function make_dpkg_dirs () {
	mkdir -p "$BUILDPLACE/var/lib/dpkg"
	: >"$BUILDPLACE/var/lib/dpkg/status"
	echo >"$BUILDPLACE/var/lib/dpkg/available"
}

function x_feign_install () {
	local pkg="$1"
	local deb="$(debfor $pkg)"
	local ver="$(
		ar -p "$BUILDPLACE/$deb" control.tar.gz | zcat |
			tar -O -xf - control ./control 2>/dev/null |
			sed -ne 's/^Version: *//Ip' | head -n 1
		)"
	mkdir -p "$BUILDPLACE/var/lib/dpkg/info"
	echo \
"Package: $pkg
Version: $ver
Status: install ok installed" >> "$BUILDPLACE/var/lib/dpkg/status"
	touch "$BUILDPLACE/var/lib/dpkg/info/${pkg}.list"
}

function prepare_proc () {
	if [ ! -d $BUILDPLACE/proc ]; then
		mkdir -p $BUILDPLACE/proc
	fi
	if [ ! -d $BUILDPLACE/sys ]; then
		mkdir -p $BUILDPLACE/sys
	fi
}

function prepare_var () {
	if [ ! -d $BUILDPLACE/var/log ]; then
		mkdir -p $BUILDPLACE/var/log
	fi
	if [ ! -d $BUILDPLACE/var/spool ]; then
		mkdir -p $BUILDPLACE/var/spool
	fi
}

function busybox_inittab () {
	if [ ! -e "$BUILDPLACE/etc/inittab" ]; then
		info INSTCORE "Adding default busybox inittab"
		echo \
"# /etc/inittab
#
# Copyright (C) 2001 Erik Andersen <andersen@codepoet.org>
#
# Note: BusyBox init doesn't support runlevels.

# Startup the system
null::sysinit:/bin/mount -o remount,rw /
null::sysinit:/bin/mount -t proc proc /proc
null::sysinit:/bin/mount -t sysfs sysfs /sys
null::sysinit:/bin/mount -t devpts devpts /dev/pts
null::sysinit:/bin/mount -a
null::sysinit:/bin/hostname -F /etc/hostname
null::sysinit:/sbin/ifconfig lo 127.0.0.1 up
null::sysinit:/sbin/route add -net 127.0.0.0 netmask 255.0.0.0 lo
# now run any rc scripts and then login
::sysinit:/etc/init.d/rcS

# Set up a couple of getty's
tty1::respawn:/sbin/getty 38400 tty1
tty2::respawn:/sbin/getty 38400 tty2

# Put a getty on the serial port
#ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100
ttyS2::respawn:/sbin/getty -L ttyS2 115200 vt100

# Logging junk
null::sysinit:/bin/touch /var/log/messages
null::respawn:/sbin/syslogd -n -m 0
null::respawn:/sbin/klogd -n
tty3::respawn:/usr/bin/tail -f /var/log/messages

# Stuff to do for the 3-finger salute
::ctrlaltdel:/sbin/reboot

# Stuff to do before rebooting
null::shutdown:/usr/bin/killall klogd
null::shutdown:/usr/bin/killall syslogd
null::shutdown:/bin/umount -a -r
null::shutdown:/sbin/swapoff -a
" > $BUILDPLACE/etc/inittab
	fi
}

function busybox_rcS () {
	if [ ! -d "$BUILDPLACE/etc/default" ]; then
		mkdir -p $BUILDPLACE/etc/default
	fi
	if [ ! -f "$BUILDPLACE/etc/default/rcS" ]; then
		echo "#!/bin/sh" > $BUILDPLACE/etc/default/rcS
		echo >> $BUILDPLACE/etc/default/rcS
		chown 0.0 "$BUILDPLACE/etc/default/rcS"
		chmod 644 "$BUILDPLACE/etc/default/rcS"
	fi
	# derived from the buildroot version.
	if [ ! -e "$BUILDPLACE/etc/init.d/rcS" ]; then
		info INSTCORE "Adding default busybox rcS"
		echo \
"#!/bin/sh
set -e
# Start all init scripts in /etc/rc.d/
#
if [ ! -z \"\$SPAWNED\" ]; then
	/bin/login
fi
SPAWNED=\"\$SPAWNED .\"
export SPAWNED=\$SPAWNED
for i in /etc/rc.d/S??* ;do
	# Ignore dangling symlinks (if any).
	[ ! -f \"\$i\" ] && continue
	case \"\$i\" in
	*.sh)
		# Source shell script for speed.
		(
		trap - INT QUIT TSTP
		set start
		. \$i
		)
		;;
	*)
		# No sh extension, so fork subprocess.
		\$i start
		;;
	esac
done
" > $BUILDPLACE/etc/init.d/rcS
	chown 0.0 "$BUILDPLACE/etc/init.d/rcS"
	chmod 755 "$BUILDPLACE/etc/init.d/rcS"
	fi
}

# call repeatedly to create init symlinks.
# arg1 is the file in $BUILDPLACE/etc/init.d/
# arg2 is the number for the link in the init sequence
# where 'foo 20' runs after 'bar 10' etc.
function symlink_rcS () {
	local file="$1"
	local num="$2"
	linkname="S$num$file"
	if [ ! -d "$BUILDPLACE/etc/rc.d/" ]; then
		mkdir $BUILDPLACE/etc/rc.d
	fi
	if [ -f $BUILDPLACE/etc/init.d/$file ]; then
		ln -sf ../init.d/$file $BUILDPLACE/etc/rc.d/$linkname
	fi
}

function symlink_rcK () {
	local file="$1"
	local num="$2"
	linkname="K$num$file"
	if [ ! -d "$BUILDPLACE/etc/rc.d/" ]; then
		mkdir $BUILDPLACE/etc/rc.d
	fi
	if [ -f $BUILDPLACE/etc/init.d/$file ]; then
		ln -sf ../init.d/$file $BUILDPLACE/etc/rc.d/$linkname
	fi
}

function set_cdebconf_default () {
	echo "export DEBCONF_USE_CDEBCONF=true" >> $BUILDPLACE/etc/profile
}

function shell_update_rcd () {
	if [ ! -e "$BUILDPLACE/usr/sbin/update-rc.d" ]; then
		info INSTCORE "Adding a /usr/sbin/update-rc.d shell script"
		cp /usr/share/emdebian-tools/update-rc.d $BUILDPLACE/usr/sbin/
		chmod 0755 $BUILDPLACE/usr/sbin/update-rc.d
	fi
}
